root / pithos / api / functions.py @ 3436eeb0
History | View | Annotate | Download (27.7 kB)
1 | 5635f9ef | Antony Chazapis | # Copyright 2011 GRNET S.A. All rights reserved.
|
---|---|---|---|
2 | 5635f9ef | Antony Chazapis | #
|
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 | 5635f9ef | Antony Chazapis | #
|
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 | 5635f9ef | Antony Chazapis | #
|
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 | 5635f9ef | Antony Chazapis | #
|
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 | 5635f9ef | Antony Chazapis | #
|
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 | b956618e | Antony Chazapis | import os |
35 | b956618e | Antony Chazapis | import logging |
36 | b956618e | Antony Chazapis | import hashlib |
37 | b956618e | Antony Chazapis | |
38 | b956618e | Antony Chazapis | from django.http import HttpResponse |
39 | b956618e | Antony Chazapis | from django.template.loader import render_to_string |
40 | b956618e | Antony Chazapis | from django.utils import simplejson as json |
41 | b956618e | Antony Chazapis | from django.utils.http import parse_etags |
42 | b956618e | Antony Chazapis | |
43 | b956618e | Antony Chazapis | from pithos.api.faults import (Fault, NotModified, BadRequest, Unauthorized, ItemNotFound, Conflict, |
44 | b956618e | Antony Chazapis | LengthRequired, PreconditionFailed, RangeNotSatisfiable, UnprocessableEntity) |
45 | 22dab079 | Antony Chazapis | from pithos.api.util import (format_meta_key, printable_meta_dict, get_account_meta, |
46 | 22dab079 | Antony Chazapis | put_account_meta, get_container_meta, put_container_meta, get_object_meta, put_object_meta, |
47 | 3436eeb0 | Antony Chazapis | update_manifest_meta, format_permissions, validate_modification_preconditions, |
48 | 3436eeb0 | Antony Chazapis | validate_matching_preconditions, split_container_object_string, copy_or_move_object, |
49 | 3436eeb0 | Antony Chazapis | get_int_parameter, get_content_length, get_content_range, get_sharing, raw_input_socket, |
50 | 3436eeb0 | Antony Chazapis | socket_read_iterator, object_data_response, put_object_block, hashmap_hash, api_method) |
51 | b956618e | Antony Chazapis | from pithos.backends import backend |
52 | b956618e | Antony Chazapis | |
53 | b956618e | Antony Chazapis | |
54 | b956618e | Antony Chazapis | logger = logging.getLogger(__name__) |
55 | b956618e | Antony Chazapis | |
56 | b956618e | Antony Chazapis | |
57 | b956618e | Antony Chazapis | def top_demux(request): |
58 | b956618e | Antony Chazapis | if request.method == 'GET': |
59 | b956618e | Antony Chazapis | return authenticate(request)
|
60 | b956618e | Antony Chazapis | else:
|
61 | b956618e | Antony Chazapis | return method_not_allowed(request)
|
62 | b956618e | Antony Chazapis | |
63 | b956618e | Antony Chazapis | def account_demux(request, v_account): |
64 | b956618e | Antony Chazapis | if request.method == 'HEAD': |
65 | b956618e | Antony Chazapis | return account_meta(request, v_account)
|
66 | b956618e | Antony Chazapis | elif request.method == 'POST': |
67 | b956618e | Antony Chazapis | return account_update(request, v_account)
|
68 | 83dd59c5 | Antony Chazapis | elif request.method == 'GET': |
69 | 83dd59c5 | Antony Chazapis | return container_list(request, v_account)
|
70 | b956618e | Antony Chazapis | else:
|
71 | b956618e | Antony Chazapis | return method_not_allowed(request)
|
72 | b956618e | Antony Chazapis | |
73 | b956618e | Antony Chazapis | def container_demux(request, v_account, v_container): |
74 | b956618e | Antony Chazapis | if request.method == 'HEAD': |
75 | b956618e | Antony Chazapis | return container_meta(request, v_account, v_container)
|
76 | b956618e | Antony Chazapis | elif request.method == 'PUT': |
77 | b956618e | Antony Chazapis | return container_create(request, v_account, v_container)
|
78 | b956618e | Antony Chazapis | elif request.method == 'POST': |
79 | b956618e | Antony Chazapis | return container_update(request, v_account, v_container)
|
80 | b956618e | Antony Chazapis | elif request.method == 'DELETE': |
81 | b956618e | Antony Chazapis | return container_delete(request, v_account, v_container)
|
82 | 83dd59c5 | Antony Chazapis | elif request.method == 'GET': |
83 | 83dd59c5 | Antony Chazapis | return object_list(request, v_account, v_container)
|
84 | b956618e | Antony Chazapis | else:
|
85 | b956618e | Antony Chazapis | return method_not_allowed(request)
|
86 | b956618e | Antony Chazapis | |
87 | b956618e | Antony Chazapis | def object_demux(request, v_account, v_container, v_object): |
88 | b956618e | Antony Chazapis | if request.method == 'HEAD': |
89 | b956618e | Antony Chazapis | return object_meta(request, v_account, v_container, v_object)
|
90 | b956618e | Antony Chazapis | elif request.method == 'GET': |
91 | b956618e | Antony Chazapis | return object_read(request, v_account, v_container, v_object)
|
92 | b956618e | Antony Chazapis | elif request.method == 'PUT': |
93 | b956618e | Antony Chazapis | return object_write(request, v_account, v_container, v_object)
|
94 | b956618e | Antony Chazapis | elif request.method == 'COPY': |
95 | b956618e | Antony Chazapis | return object_copy(request, v_account, v_container, v_object)
|
96 | b956618e | Antony Chazapis | elif request.method == 'MOVE': |
97 | b956618e | Antony Chazapis | return object_move(request, v_account, v_container, v_object)
|
98 | b956618e | Antony Chazapis | elif request.method == 'POST': |
99 | b956618e | Antony Chazapis | return object_update(request, v_account, v_container, v_object)
|
100 | b956618e | Antony Chazapis | elif request.method == 'DELETE': |
101 | b956618e | Antony Chazapis | return object_delete(request, v_account, v_container, v_object)
|
102 | b956618e | Antony Chazapis | else:
|
103 | b956618e | Antony Chazapis | return method_not_allowed(request)
|
104 | b956618e | Antony Chazapis | |
105 | b956618e | Antony Chazapis | @api_method('GET') |
106 | b956618e | Antony Chazapis | def authenticate(request): |
107 | b956618e | Antony Chazapis | # Normal Response Codes: 204
|
108 | b956618e | Antony Chazapis | # Error Response Codes: serviceUnavailable (503),
|
109 | b956618e | Antony Chazapis | # unauthorized (401),
|
110 | b956618e | Antony Chazapis | # badRequest (400)
|
111 | b956618e | Antony Chazapis | |
112 | b956618e | Antony Chazapis | x_auth_user = request.META.get('HTTP_X_AUTH_USER')
|
113 | b956618e | Antony Chazapis | x_auth_key = request.META.get('HTTP_X_AUTH_KEY')
|
114 | b956618e | Antony Chazapis | if not x_auth_user or not x_auth_key: |
115 | b956618e | Antony Chazapis | raise BadRequest('Missing X-Auth-User or X-Auth-Key header') |
116 | b956618e | Antony Chazapis | response = HttpResponse(status=204)
|
117 | b956618e | Antony Chazapis | response['X-Auth-Token'] = '0000' |
118 | b956618e | Antony Chazapis | response['X-Storage-Url'] = os.path.join(request.build_absolute_uri(), 'demo') |
119 | b956618e | Antony Chazapis | return response
|
120 | b956618e | Antony Chazapis | |
121 | b956618e | Antony Chazapis | @api_method('HEAD') |
122 | b956618e | Antony Chazapis | def account_meta(request, v_account): |
123 | b956618e | Antony Chazapis | # Normal Response Codes: 204
|
124 | b956618e | Antony Chazapis | # Error Response Codes: serviceUnavailable (503),
|
125 | b956618e | Antony Chazapis | # unauthorized (401),
|
126 | b956618e | Antony Chazapis | # badRequest (400)
|
127 | b956618e | Antony Chazapis | |
128 | 83dd59c5 | Antony Chazapis | until = get_int_parameter(request, 'until')
|
129 | 83dd59c5 | Antony Chazapis | meta = backend.get_account_meta(request.user, v_account, until) |
130 | b956618e | Antony Chazapis | |
131 | b956618e | Antony Chazapis | response = HttpResponse(status=204)
|
132 | b956618e | Antony Chazapis | put_account_meta(response, meta) |
133 | b956618e | Antony Chazapis | return response
|
134 | b956618e | Antony Chazapis | |
135 | b956618e | Antony Chazapis | @api_method('POST') |
136 | b956618e | Antony Chazapis | def account_update(request, v_account): |
137 | b956618e | Antony Chazapis | # Normal Response Codes: 202
|
138 | b956618e | Antony Chazapis | # Error Response Codes: serviceUnavailable (503),
|
139 | b956618e | Antony Chazapis | # unauthorized (401),
|
140 | b956618e | Antony Chazapis | # badRequest (400)
|
141 | b956618e | Antony Chazapis | |
142 | b956618e | Antony Chazapis | meta = get_account_meta(request) |
143 | 83dd59c5 | Antony Chazapis | backend.update_account_meta(request.user, v_account, meta, replace=True)
|
144 | b956618e | Antony Chazapis | return HttpResponse(status=202) |
145 | b956618e | Antony Chazapis | |
146 | b956618e | Antony Chazapis | @api_method('GET', format_allowed=True) |
147 | b956618e | Antony Chazapis | def container_list(request, v_account): |
148 | b956618e | Antony Chazapis | # Normal Response Codes: 200, 204
|
149 | b956618e | Antony Chazapis | # Error Response Codes: serviceUnavailable (503),
|
150 | b956618e | Antony Chazapis | # itemNotFound (404),
|
151 | b956618e | Antony Chazapis | # unauthorized (401),
|
152 | b956618e | Antony Chazapis | # badRequest (400)
|
153 | b956618e | Antony Chazapis | |
154 | 83dd59c5 | Antony Chazapis | until = get_int_parameter(request, 'until')
|
155 | 83dd59c5 | Antony Chazapis | meta = backend.get_account_meta(request.user, v_account, until) |
156 | b956618e | Antony Chazapis | |
157 | b956618e | Antony Chazapis | validate_modification_preconditions(request, meta) |
158 | b956618e | Antony Chazapis | |
159 | b956618e | Antony Chazapis | response = HttpResponse() |
160 | b956618e | Antony Chazapis | put_account_meta(response, meta) |
161 | b956618e | Antony Chazapis | |
162 | b956618e | Antony Chazapis | marker = request.GET.get('marker')
|
163 | b956618e | Antony Chazapis | limit = request.GET.get('limit')
|
164 | b956618e | Antony Chazapis | if limit:
|
165 | b956618e | Antony Chazapis | try:
|
166 | b956618e | Antony Chazapis | limit = int(limit)
|
167 | b956618e | Antony Chazapis | if limit <= 0: |
168 | b956618e | Antony Chazapis | raise ValueError |
169 | b956618e | Antony Chazapis | except ValueError: |
170 | b956618e | Antony Chazapis | limit = 10000
|
171 | b956618e | Antony Chazapis | |
172 | b956618e | Antony Chazapis | try:
|
173 | 83dd59c5 | Antony Chazapis | containers = backend.list_containers(request.user, v_account, marker, limit, until) |
174 | b956618e | Antony Chazapis | except NameError: |
175 | b956618e | Antony Chazapis | containers = [] |
176 | b956618e | Antony Chazapis | |
177 | b956618e | Antony Chazapis | if request.serialization == 'text': |
178 | b956618e | Antony Chazapis | if len(containers) == 0: |
179 | b956618e | Antony Chazapis | # The cloudfiles python bindings expect 200 if json/xml.
|
180 | b956618e | Antony Chazapis | response.status_code = 204
|
181 | b956618e | Antony Chazapis | return response
|
182 | b956618e | Antony Chazapis | response.status_code = 200
|
183 | 83dd59c5 | Antony Chazapis | response.content = '\n'.join([x[0] for x in containers]) + '\n' |
184 | b956618e | Antony Chazapis | return response
|
185 | b956618e | Antony Chazapis | |
186 | b956618e | Antony Chazapis | container_meta = [] |
187 | b956618e | Antony Chazapis | for x in containers: |
188 | 83dd59c5 | Antony Chazapis | if x[1] is not None: |
189 | 83dd59c5 | Antony Chazapis | try:
|
190 | 83dd59c5 | Antony Chazapis | meta = backend.get_container_meta(request.user, v_account, x[0], until)
|
191 | 83dd59c5 | Antony Chazapis | container_meta.append(printable_meta_dict(meta)) |
192 | 83dd59c5 | Antony Chazapis | except NameError: |
193 | 83dd59c5 | Antony Chazapis | pass
|
194 | b956618e | Antony Chazapis | if request.serialization == 'xml': |
195 | 2c22e4ac | Antony Chazapis | data = render_to_string('containers.xml', {'account': v_account, 'containers': container_meta}) |
196 | b956618e | Antony Chazapis | elif request.serialization == 'json': |
197 | b956618e | Antony Chazapis | data = json.dumps(container_meta) |
198 | b956618e | Antony Chazapis | response.status_code = 200
|
199 | b956618e | Antony Chazapis | response.content = data |
200 | b956618e | Antony Chazapis | return response
|
201 | b956618e | Antony Chazapis | |
202 | b956618e | Antony Chazapis | @api_method('HEAD') |
203 | b956618e | Antony Chazapis | def container_meta(request, v_account, v_container): |
204 | b956618e | Antony Chazapis | # Normal Response Codes: 204
|
205 | b956618e | Antony Chazapis | # Error Response Codes: serviceUnavailable (503),
|
206 | b956618e | Antony Chazapis | # itemNotFound (404),
|
207 | b956618e | Antony Chazapis | # unauthorized (401),
|
208 | b956618e | Antony Chazapis | # badRequest (400)
|
209 | b956618e | Antony Chazapis | |
210 | 83dd59c5 | Antony Chazapis | until = get_int_parameter(request, 'until')
|
211 | b956618e | Antony Chazapis | try:
|
212 | 83dd59c5 | Antony Chazapis | meta = backend.get_container_meta(request.user, v_account, v_container, until) |
213 | 83dd59c5 | Antony Chazapis | meta['object_meta'] = backend.list_object_meta(request.user, v_account, v_container, until)
|
214 | b956618e | Antony Chazapis | except NameError: |
215 | b956618e | Antony Chazapis | raise ItemNotFound('Container does not exist') |
216 | b956618e | Antony Chazapis | |
217 | b956618e | Antony Chazapis | response = HttpResponse(status=204)
|
218 | b956618e | Antony Chazapis | put_container_meta(response, meta) |
219 | b956618e | Antony Chazapis | return response
|
220 | b956618e | Antony Chazapis | |
221 | b956618e | Antony Chazapis | @api_method('PUT') |
222 | b956618e | Antony Chazapis | def container_create(request, v_account, v_container): |
223 | b956618e | Antony Chazapis | # Normal Response Codes: 201, 202
|
224 | b956618e | Antony Chazapis | # Error Response Codes: serviceUnavailable (503),
|
225 | b956618e | Antony Chazapis | # itemNotFound (404),
|
226 | b956618e | Antony Chazapis | # unauthorized (401),
|
227 | b956618e | Antony Chazapis | # badRequest (400)
|
228 | b956618e | Antony Chazapis | |
229 | b956618e | Antony Chazapis | meta = get_container_meta(request) |
230 | b956618e | Antony Chazapis | |
231 | b956618e | Antony Chazapis | try:
|
232 | 83dd59c5 | Antony Chazapis | backend.put_container(request.user, v_account, v_container) |
233 | b956618e | Antony Chazapis | ret = 201
|
234 | b956618e | Antony Chazapis | except NameError: |
235 | b956618e | Antony Chazapis | ret = 202
|
236 | b956618e | Antony Chazapis | |
237 | b956618e | Antony Chazapis | if len(meta) > 0: |
238 | 83dd59c5 | Antony Chazapis | backend.update_container_meta(request.user, v_account, v_container, meta, replace=True)
|
239 | b956618e | Antony Chazapis | |
240 | b956618e | Antony Chazapis | return HttpResponse(status=ret)
|
241 | b956618e | Antony Chazapis | |
242 | b956618e | Antony Chazapis | @api_method('POST') |
243 | b956618e | Antony Chazapis | def container_update(request, v_account, v_container): |
244 | b956618e | Antony Chazapis | # Normal Response Codes: 202
|
245 | b956618e | Antony Chazapis | # Error Response Codes: serviceUnavailable (503),
|
246 | b956618e | Antony Chazapis | # itemNotFound (404),
|
247 | b956618e | Antony Chazapis | # unauthorized (401),
|
248 | b956618e | Antony Chazapis | # badRequest (400)
|
249 | b956618e | Antony Chazapis | |
250 | b956618e | Antony Chazapis | meta = get_container_meta(request) |
251 | b956618e | Antony Chazapis | try:
|
252 | 83dd59c5 | Antony Chazapis | backend.update_container_meta(request.user, v_account, v_container, meta, replace=True)
|
253 | b956618e | Antony Chazapis | except NameError: |
254 | b956618e | Antony Chazapis | raise ItemNotFound('Container does not exist') |
255 | b956618e | Antony Chazapis | return HttpResponse(status=202) |
256 | b956618e | Antony Chazapis | |
257 | b956618e | Antony Chazapis | @api_method('DELETE') |
258 | b956618e | Antony Chazapis | def container_delete(request, v_account, v_container): |
259 | b956618e | Antony Chazapis | # Normal Response Codes: 204
|
260 | b956618e | Antony Chazapis | # Error Response Codes: serviceUnavailable (503),
|
261 | b956618e | Antony Chazapis | # conflict (409),
|
262 | b956618e | Antony Chazapis | # itemNotFound (404),
|
263 | b956618e | Antony Chazapis | # unauthorized (401),
|
264 | b956618e | Antony Chazapis | # badRequest (400)
|
265 | b956618e | Antony Chazapis | |
266 | b956618e | Antony Chazapis | try:
|
267 | 83dd59c5 | Antony Chazapis | backend.delete_container(request.user, v_account, v_container) |
268 | b956618e | Antony Chazapis | except NameError: |
269 | b956618e | Antony Chazapis | raise ItemNotFound('Container does not exist') |
270 | b956618e | Antony Chazapis | except IndexError: |
271 | b956618e | Antony Chazapis | raise Conflict('Container is not empty') |
272 | b956618e | Antony Chazapis | return HttpResponse(status=204) |
273 | b956618e | Antony Chazapis | |
274 | b956618e | Antony Chazapis | @api_method('GET', format_allowed=True) |
275 | b956618e | Antony Chazapis | def object_list(request, v_account, v_container): |
276 | b956618e | Antony Chazapis | # Normal Response Codes: 200, 204
|
277 | b956618e | Antony Chazapis | # Error Response Codes: serviceUnavailable (503),
|
278 | b956618e | Antony Chazapis | # itemNotFound (404),
|
279 | b956618e | Antony Chazapis | # unauthorized (401),
|
280 | b956618e | Antony Chazapis | # badRequest (400)
|
281 | b956618e | Antony Chazapis | |
282 | 83dd59c5 | Antony Chazapis | until = get_int_parameter(request, 'until')
|
283 | b956618e | Antony Chazapis | try:
|
284 | 83dd59c5 | Antony Chazapis | meta = backend.get_container_meta(request.user, v_account, v_container, until) |
285 | 83dd59c5 | Antony Chazapis | meta['object_meta'] = backend.list_object_meta(request.user, v_account, v_container, until)
|
286 | b956618e | Antony Chazapis | except NameError: |
287 | b956618e | Antony Chazapis | raise ItemNotFound('Container does not exist') |
288 | b956618e | Antony Chazapis | |
289 | b956618e | Antony Chazapis | validate_modification_preconditions(request, meta) |
290 | b956618e | Antony Chazapis | |
291 | b956618e | Antony Chazapis | response = HttpResponse() |
292 | b956618e | Antony Chazapis | put_container_meta(response, meta) |
293 | b956618e | Antony Chazapis | |
294 | b956618e | Antony Chazapis | path = request.GET.get('path')
|
295 | b956618e | Antony Chazapis | prefix = request.GET.get('prefix')
|
296 | b956618e | Antony Chazapis | delimiter = request.GET.get('delimiter')
|
297 | b956618e | Antony Chazapis | |
298 | b956618e | Antony Chazapis | # Path overrides prefix and delimiter.
|
299 | b956618e | Antony Chazapis | virtual = True
|
300 | b956618e | Antony Chazapis | if path:
|
301 | b956618e | Antony Chazapis | prefix = path |
302 | b956618e | Antony Chazapis | delimiter = '/'
|
303 | b956618e | Antony Chazapis | virtual = False
|
304 | b956618e | Antony Chazapis | |
305 | b956618e | Antony Chazapis | # Naming policy.
|
306 | b956618e | Antony Chazapis | if prefix and delimiter: |
307 | b956618e | Antony Chazapis | prefix = prefix + delimiter |
308 | b956618e | Antony Chazapis | if not prefix: |
309 | b956618e | Antony Chazapis | prefix = ''
|
310 | b956618e | Antony Chazapis | prefix = prefix.lstrip('/')
|
311 | b956618e | Antony Chazapis | |
312 | b956618e | Antony Chazapis | marker = request.GET.get('marker')
|
313 | b956618e | Antony Chazapis | limit = request.GET.get('limit')
|
314 | b956618e | Antony Chazapis | if limit:
|
315 | b956618e | Antony Chazapis | try:
|
316 | b956618e | Antony Chazapis | limit = int(limit)
|
317 | b956618e | Antony Chazapis | if limit <= 0: |
318 | b956618e | Antony Chazapis | raise ValueError |
319 | b956618e | Antony Chazapis | except ValueError: |
320 | b956618e | Antony Chazapis | limit = 10000
|
321 | b956618e | Antony Chazapis | |
322 | 22dab079 | Antony Chazapis | keys = request.GET.get('meta')
|
323 | 22dab079 | Antony Chazapis | if keys:
|
324 | 22dab079 | Antony Chazapis | keys = keys.split(',')
|
325 | 22dab079 | Antony Chazapis | keys = [format_meta_key('X-Object-Meta-' + x.strip()) for x in keys if x.strip() != ''] |
326 | 22dab079 | Antony Chazapis | else:
|
327 | 22dab079 | Antony Chazapis | keys = [] |
328 | 22dab079 | Antony Chazapis | |
329 | b956618e | Antony Chazapis | try:
|
330 | 83dd59c5 | Antony Chazapis | objects = backend.list_objects(request.user, v_account, v_container, prefix, delimiter, marker, limit, virtual, keys, until) |
331 | b956618e | Antony Chazapis | except NameError: |
332 | b956618e | Antony Chazapis | raise ItemNotFound('Container does not exist') |
333 | b956618e | Antony Chazapis | |
334 | b956618e | Antony Chazapis | if request.serialization == 'text': |
335 | b956618e | Antony Chazapis | if len(objects) == 0: |
336 | b956618e | Antony Chazapis | # The cloudfiles python bindings expect 200 if json/xml.
|
337 | b956618e | Antony Chazapis | response.status_code = 204
|
338 | b956618e | Antony Chazapis | return response
|
339 | b956618e | Antony Chazapis | response.status_code = 200
|
340 | 83dd59c5 | Antony Chazapis | response.content = '\n'.join([x[0] for x in objects]) + '\n' |
341 | b956618e | Antony Chazapis | return response
|
342 | b956618e | Antony Chazapis | |
343 | b956618e | Antony Chazapis | object_meta = [] |
344 | b956618e | Antony Chazapis | for x in objects: |
345 | 83dd59c5 | Antony Chazapis | if x[1] is None: |
346 | b956618e | Antony Chazapis | # Virtual objects/directories.
|
347 | 83dd59c5 | Antony Chazapis | object_meta.append({'subdir': x[0]}) |
348 | 83dd59c5 | Antony Chazapis | else:
|
349 | 83dd59c5 | Antony Chazapis | try:
|
350 | 83dd59c5 | Antony Chazapis | meta = backend.get_object_meta(request.user, v_account, v_container, x[0], x[1]) |
351 | 3436eeb0 | Antony Chazapis | permissions = backend.get_object_permissions(request.user, v_account, v_container, x[0])
|
352 | 83dd59c5 | Antony Chazapis | except NameError: |
353 | 83dd59c5 | Antony Chazapis | pass
|
354 | 3436eeb0 | Antony Chazapis | if permissions:
|
355 | 3436eeb0 | Antony Chazapis | meta['X-Object-Sharing'] = format_permissions(permissions)
|
356 | 3436eeb0 | Antony Chazapis | object_meta.append(printable_meta_dict(meta)) |
357 | b956618e | Antony Chazapis | if request.serialization == 'xml': |
358 | b956618e | Antony Chazapis | data = render_to_string('objects.xml', {'container': v_container, 'objects': object_meta}) |
359 | b956618e | Antony Chazapis | elif request.serialization == 'json': |
360 | b956618e | Antony Chazapis | data = json.dumps(object_meta) |
361 | b956618e | Antony Chazapis | response.status_code = 200
|
362 | b956618e | Antony Chazapis | response.content = data |
363 | b956618e | Antony Chazapis | return response
|
364 | b956618e | Antony Chazapis | |
365 | b956618e | Antony Chazapis | @api_method('HEAD') |
366 | b956618e | Antony Chazapis | def object_meta(request, v_account, v_container, v_object): |
367 | b956618e | Antony Chazapis | # Normal Response Codes: 204
|
368 | b956618e | Antony Chazapis | # Error Response Codes: serviceUnavailable (503),
|
369 | b956618e | Antony Chazapis | # itemNotFound (404),
|
370 | b956618e | Antony Chazapis | # unauthorized (401),
|
371 | b956618e | Antony Chazapis | # badRequest (400)
|
372 | b956618e | Antony Chazapis | |
373 | 83dd59c5 | Antony Chazapis | version = get_int_parameter(request, 'version')
|
374 | b956618e | Antony Chazapis | try:
|
375 | 83dd59c5 | Antony Chazapis | meta = backend.get_object_meta(request.user, v_account, v_container, v_object, version) |
376 | 3436eeb0 | Antony Chazapis | permissions = backend.get_object_permissions(request.user, v_account, v_container, v_object) |
377 | b956618e | Antony Chazapis | except NameError: |
378 | b956618e | Antony Chazapis | raise ItemNotFound('Object does not exist') |
379 | 58a6c894 | Antony Chazapis | except IndexError: |
380 | 58a6c894 | Antony Chazapis | raise ItemNotFound('Version does not exist') |
381 | b956618e | Antony Chazapis | |
382 | 3436eeb0 | Antony Chazapis | if permissions:
|
383 | 3436eeb0 | Antony Chazapis | meta['X-Object-Sharing'] = format_permissions(permissions)
|
384 | 8cb45c13 | Antony Chazapis | update_manifest_meta(request, v_account, meta) |
385 | 8cb45c13 | Antony Chazapis | |
386 | cb146cf9 | Antony Chazapis | response = HttpResponse(status=200)
|
387 | b956618e | Antony Chazapis | put_object_meta(response, meta) |
388 | b956618e | Antony Chazapis | return response
|
389 | b956618e | Antony Chazapis | |
390 | 22dab079 | Antony Chazapis | @api_method('GET', format_allowed=True) |
391 | b956618e | Antony Chazapis | def object_read(request, v_account, v_container, v_object): |
392 | b956618e | Antony Chazapis | # Normal Response Codes: 200, 206
|
393 | b956618e | Antony Chazapis | # Error Response Codes: serviceUnavailable (503),
|
394 | b956618e | Antony Chazapis | # rangeNotSatisfiable (416),
|
395 | b956618e | Antony Chazapis | # preconditionFailed (412),
|
396 | b956618e | Antony Chazapis | # itemNotFound (404),
|
397 | b956618e | Antony Chazapis | # unauthorized (401),
|
398 | b956618e | Antony Chazapis | # badRequest (400),
|
399 | b956618e | Antony Chazapis | # notModified (304)
|
400 | b956618e | Antony Chazapis | |
401 | 83dd59c5 | Antony Chazapis | version = get_int_parameter(request, 'version')
|
402 | cb146cf9 | Antony Chazapis | version_list = False
|
403 | cb146cf9 | Antony Chazapis | if version is None and request.GET.get('version') == 'list': |
404 | cb146cf9 | Antony Chazapis | version_list = True
|
405 | b956618e | Antony Chazapis | try:
|
406 | 83dd59c5 | Antony Chazapis | meta = backend.get_object_meta(request.user, v_account, v_container, v_object, version) |
407 | 3436eeb0 | Antony Chazapis | permissions = backend.get_object_permissions(request.user, v_account, v_container, v_object) |
408 | b956618e | Antony Chazapis | except NameError: |
409 | b956618e | Antony Chazapis | raise ItemNotFound('Object does not exist') |
410 | 58a6c894 | Antony Chazapis | except IndexError: |
411 | 58a6c894 | Antony Chazapis | raise ItemNotFound('Version does not exist') |
412 | b956618e | Antony Chazapis | |
413 | 3436eeb0 | Antony Chazapis | if permissions:
|
414 | 3436eeb0 | Antony Chazapis | meta['X-Object-Sharing'] = format_permissions(permissions)
|
415 | 8cb45c13 | Antony Chazapis | update_manifest_meta(request, v_account, meta) |
416 | 8cb45c13 | Antony Chazapis | |
417 | 22dab079 | Antony Chazapis | # Evaluate conditions.
|
418 | b956618e | Antony Chazapis | validate_modification_preconditions(request, meta) |
419 | 22dab079 | Antony Chazapis | try:
|
420 | 22dab079 | Antony Chazapis | validate_matching_preconditions(request, meta) |
421 | 22dab079 | Antony Chazapis | except NotModified:
|
422 | 22dab079 | Antony Chazapis | response = HttpResponse(status=304)
|
423 | 22dab079 | Antony Chazapis | response['ETag'] = meta['hash'] |
424 | 22dab079 | Antony Chazapis | return response
|
425 | b956618e | Antony Chazapis | |
426 | 83dd59c5 | Antony Chazapis | # Reply with the version list.
|
427 | cb146cf9 | Antony Chazapis | if version_list:
|
428 | 83dd59c5 | Antony Chazapis | if request.serialization == 'text': |
429 | 83dd59c5 | Antony Chazapis | raise BadRequest('No format specified for version list.') |
430 | 83dd59c5 | Antony Chazapis | |
431 | 83dd59c5 | Antony Chazapis | d = {'versions': backend.list_versions(request.user, v_account, v_container, v_object)}
|
432 | 83dd59c5 | Antony Chazapis | if request.serialization == 'xml': |
433 | 83dd59c5 | Antony Chazapis | d['object'] = v_object
|
434 | 83dd59c5 | Antony Chazapis | data = render_to_string('versions.xml', d)
|
435 | 83dd59c5 | Antony Chazapis | elif request.serialization == 'json': |
436 | 83dd59c5 | Antony Chazapis | data = json.dumps(d) |
437 | 83dd59c5 | Antony Chazapis | |
438 | 83dd59c5 | Antony Chazapis | response = HttpResponse(data, status=200)
|
439 | 83dd59c5 | Antony Chazapis | put_object_meta(response, meta) |
440 | 83dd59c5 | Antony Chazapis | response['Content-Length'] = len(data) |
441 | 83dd59c5 | Antony Chazapis | return response
|
442 | 83dd59c5 | Antony Chazapis | |
443 | 8cb45c13 | Antony Chazapis | sizes = [] |
444 | 8cb45c13 | Antony Chazapis | hashmaps = [] |
445 | 8cb45c13 | Antony Chazapis | if 'X-Object-Manifest' in meta: |
446 | 8cb45c13 | Antony Chazapis | try:
|
447 | 6d817842 | Antony Chazapis | src_container, src_name = split_container_object_string('/' + meta['X-Object-Manifest']) |
448 | 8cb45c13 | Antony Chazapis | objects = backend.list_objects(request.user, v_account, src_container, prefix=src_name, virtual=False)
|
449 | 8cb45c13 | Antony Chazapis | except ValueError: |
450 | 8cb45c13 | Antony Chazapis | raise BadRequest('Invalid X-Object-Manifest header') |
451 | 8cb45c13 | Antony Chazapis | except NameError: |
452 | 8cb45c13 | Antony Chazapis | raise ItemNotFound('Container does not exist') |
453 | 8cb45c13 | Antony Chazapis | |
454 | 8cb45c13 | Antony Chazapis | try:
|
455 | 8cb45c13 | Antony Chazapis | for x in objects: |
456 | 8cb45c13 | Antony Chazapis | s, h = backend.get_object_hashmap(request.user, v_account, src_container, x[0], x[1]) |
457 | 8cb45c13 | Antony Chazapis | sizes.append(s) |
458 | 8cb45c13 | Antony Chazapis | hashmaps.append(h) |
459 | 8cb45c13 | Antony Chazapis | except NameError: |
460 | 8cb45c13 | Antony Chazapis | raise ItemNotFound('Object does not exist') |
461 | 8cb45c13 | Antony Chazapis | except IndexError: |
462 | 8cb45c13 | Antony Chazapis | raise ItemNotFound('Version does not exist') |
463 | 8cb45c13 | Antony Chazapis | else:
|
464 | 8cb45c13 | Antony Chazapis | try:
|
465 | 8cb45c13 | Antony Chazapis | s, h = backend.get_object_hashmap(request.user, v_account, v_container, v_object, version) |
466 | 8cb45c13 | Antony Chazapis | sizes.append(s) |
467 | 8cb45c13 | Antony Chazapis | hashmaps.append(h) |
468 | 8cb45c13 | Antony Chazapis | except NameError: |
469 | 8cb45c13 | Antony Chazapis | raise ItemNotFound('Object does not exist') |
470 | 8cb45c13 | Antony Chazapis | except IndexError: |
471 | 8cb45c13 | Antony Chazapis | raise ItemNotFound('Version does not exist') |
472 | b956618e | Antony Chazapis | |
473 | 22dab079 | Antony Chazapis | # Reply with the hashmap.
|
474 | 22dab079 | Antony Chazapis | if request.serialization != 'text': |
475 | 8cb45c13 | Antony Chazapis | size = sum(sizes)
|
476 | 8cb45c13 | Antony Chazapis | hashmap = sum(hashmaps, [])
|
477 | 6bc372a4 | Antony Chazapis | d = {'block_size': backend.block_size, 'block_hash': backend.hash_algorithm, 'bytes': size, 'hashes': hashmap} |
478 | 22dab079 | Antony Chazapis | if request.serialization == 'xml': |
479 | 6bc372a4 | Antony Chazapis | d['object'] = v_object
|
480 | 6bc372a4 | Antony Chazapis | data = render_to_string('hashes.xml', d)
|
481 | 22dab079 | Antony Chazapis | elif request.serialization == 'json': |
482 | 6bc372a4 | Antony Chazapis | data = json.dumps(d) |
483 | 22dab079 | Antony Chazapis | |
484 | 22dab079 | Antony Chazapis | response = HttpResponse(data, status=200)
|
485 | 22dab079 | Antony Chazapis | put_object_meta(response, meta) |
486 | 22dab079 | Antony Chazapis | response['Content-Length'] = len(data) |
487 | 22dab079 | Antony Chazapis | return response
|
488 | 22dab079 | Antony Chazapis | |
489 | 8cb45c13 | Antony Chazapis | return object_data_response(request, sizes, hashmaps, meta)
|
490 | b956618e | Antony Chazapis | |
491 | b956618e | Antony Chazapis | @api_method('PUT') |
492 | b956618e | Antony Chazapis | def object_write(request, v_account, v_container, v_object): |
493 | b956618e | Antony Chazapis | # Normal Response Codes: 201
|
494 | b956618e | Antony Chazapis | # Error Response Codes: serviceUnavailable (503),
|
495 | b956618e | Antony Chazapis | # unprocessableEntity (422),
|
496 | b956618e | Antony Chazapis | # lengthRequired (411),
|
497 | 3436eeb0 | Antony Chazapis | # conflict (409),
|
498 | b956618e | Antony Chazapis | # itemNotFound (404),
|
499 | b956618e | Antony Chazapis | # unauthorized (401),
|
500 | b956618e | Antony Chazapis | # badRequest (400)
|
501 | b956618e | Antony Chazapis | |
502 | b956618e | Antony Chazapis | copy_from = request.META.get('HTTP_X_COPY_FROM')
|
503 | b956618e | Antony Chazapis | move_from = request.META.get('HTTP_X_MOVE_FROM')
|
504 | b956618e | Antony Chazapis | if copy_from or move_from: |
505 | b956618e | Antony Chazapis | # TODO: Why is this required? Copy this ammount?
|
506 | 22dab079 | Antony Chazapis | content_length = get_content_length(request) |
507 | b956618e | Antony Chazapis | |
508 | b956618e | Antony Chazapis | if move_from:
|
509 | 83dd59c5 | Antony Chazapis | try:
|
510 | 83dd59c5 | Antony Chazapis | src_container, src_name = split_container_object_string(move_from) |
511 | 83dd59c5 | Antony Chazapis | except ValueError: |
512 | 83dd59c5 | Antony Chazapis | raise BadRequest('Invalid X-Move-From header') |
513 | 83dd59c5 | Antony Chazapis | copy_or_move_object(request, v_account, src_container, src_name, v_container, v_object, move=True)
|
514 | b956618e | Antony Chazapis | else:
|
515 | 83dd59c5 | Antony Chazapis | try:
|
516 | 83dd59c5 | Antony Chazapis | src_container, src_name = split_container_object_string(copy_from) |
517 | 83dd59c5 | Antony Chazapis | except ValueError: |
518 | 83dd59c5 | Antony Chazapis | raise BadRequest('Invalid X-Copy-From header') |
519 | 83dd59c5 | Antony Chazapis | copy_or_move_object(request, v_account, src_container, src_name, v_container, v_object, move=False)
|
520 | b956618e | Antony Chazapis | return HttpResponse(status=201) |
521 | b956618e | Antony Chazapis | |
522 | b956618e | Antony Chazapis | meta = get_object_meta(request) |
523 | 3436eeb0 | Antony Chazapis | permissions = get_sharing(request) |
524 | b956618e | Antony Chazapis | content_length = -1
|
525 | b956618e | Antony Chazapis | if request.META.get('HTTP_TRANSFER_ENCODING') != 'chunked': |
526 | 22dab079 | Antony Chazapis | content_length = get_content_length(request) |
527 | b956618e | Antony Chazapis | # Should be BadRequest, but API says otherwise.
|
528 | b956618e | Antony Chazapis | if 'Content-Type' not in meta: |
529 | b956618e | Antony Chazapis | raise LengthRequired('Missing Content-Type header') |
530 | b956618e | Antony Chazapis | |
531 | b956618e | Antony Chazapis | md5 = hashlib.md5() |
532 | 58a6c894 | Antony Chazapis | size = 0
|
533 | 58a6c894 | Antony Chazapis | hashmap = [] |
534 | 58a6c894 | Antony Chazapis | sock = raw_input_socket(request) |
535 | 58a6c894 | Antony Chazapis | for data in socket_read_iterator(sock, content_length, backend.block_size): |
536 | 58a6c894 | Antony Chazapis | # TODO: Raise 408 (Request Timeout) if this takes too long.
|
537 | 58a6c894 | Antony Chazapis | # TODO: Raise 499 (Client Disconnect) if a length is defined and we stop before getting this much data.
|
538 | 58a6c894 | Antony Chazapis | size += len(data)
|
539 | 58a6c894 | Antony Chazapis | hashmap.append(backend.put_block(data)) |
540 | 58a6c894 | Antony Chazapis | md5.update(data) |
541 | b956618e | Antony Chazapis | |
542 | b956618e | Antony Chazapis | meta['hash'] = md5.hexdigest().lower()
|
543 | b956618e | Antony Chazapis | etag = request.META.get('HTTP_ETAG')
|
544 | b956618e | Antony Chazapis | if etag and parse_etags(etag)[0].lower() != meta['hash']: |
545 | 22dab079 | Antony Chazapis | raise UnprocessableEntity('Object ETag does not match') |
546 | 22dab079 | Antony Chazapis | |
547 | 22dab079 | Antony Chazapis | try:
|
548 | 3436eeb0 | Antony Chazapis | backend.update_object_hashmap(request.user, v_account, v_container, v_object, size, hashmap, meta, True, permissions)
|
549 | 22dab079 | Antony Chazapis | except NameError: |
550 | 22dab079 | Antony Chazapis | raise ItemNotFound('Container does not exist') |
551 | 3436eeb0 | Antony Chazapis | except ValueError: |
552 | 3436eeb0 | Antony Chazapis | raise BadRequest('Invalid sharing header') |
553 | 3436eeb0 | Antony Chazapis | except AttributeError: |
554 | 3436eeb0 | Antony Chazapis | raise Conflict('Sharing already set above or below this path in the hierarchy') |
555 | b956618e | Antony Chazapis | |
556 | b956618e | Antony Chazapis | response = HttpResponse(status=201)
|
557 | b956618e | Antony Chazapis | response['ETag'] = meta['hash'] |
558 | b956618e | Antony Chazapis | return response
|
559 | b956618e | Antony Chazapis | |
560 | b956618e | Antony Chazapis | @api_method('COPY') |
561 | b956618e | Antony Chazapis | def object_copy(request, v_account, v_container, v_object): |
562 | b956618e | Antony Chazapis | # Normal Response Codes: 201
|
563 | b956618e | Antony Chazapis | # Error Response Codes: serviceUnavailable (503),
|
564 | b956618e | Antony Chazapis | # itemNotFound (404),
|
565 | b956618e | Antony Chazapis | # unauthorized (401),
|
566 | b956618e | Antony Chazapis | # badRequest (400)
|
567 | b956618e | Antony Chazapis | |
568 | b956618e | Antony Chazapis | dest_path = request.META.get('HTTP_DESTINATION')
|
569 | b956618e | Antony Chazapis | if not dest_path: |
570 | b956618e | Antony Chazapis | raise BadRequest('Missing Destination header') |
571 | 83dd59c5 | Antony Chazapis | try:
|
572 | 83dd59c5 | Antony Chazapis | dest_container, dest_name = split_container_object_string(dest_path) |
573 | 83dd59c5 | Antony Chazapis | except ValueError: |
574 | 83dd59c5 | Antony Chazapis | raise BadRequest('Invalid Destination header') |
575 | 83dd59c5 | Antony Chazapis | copy_or_move_object(request, v_account, v_container, v_object, dest_container, dest_name, move=False)
|
576 | b956618e | Antony Chazapis | return HttpResponse(status=201) |
577 | b956618e | Antony Chazapis | |
578 | b956618e | Antony Chazapis | @api_method('MOVE') |
579 | b956618e | Antony Chazapis | def object_move(request, v_account, v_container, v_object): |
580 | b956618e | Antony Chazapis | # Normal Response Codes: 201
|
581 | b956618e | Antony Chazapis | # Error Response Codes: serviceUnavailable (503),
|
582 | b956618e | Antony Chazapis | # itemNotFound (404),
|
583 | b956618e | Antony Chazapis | # unauthorized (401),
|
584 | b956618e | Antony Chazapis | # badRequest (400)
|
585 | b956618e | Antony Chazapis | |
586 | b956618e | Antony Chazapis | dest_path = request.META.get('HTTP_DESTINATION')
|
587 | b956618e | Antony Chazapis | if not dest_path: |
588 | b956618e | Antony Chazapis | raise BadRequest('Missing Destination header') |
589 | 83dd59c5 | Antony Chazapis | try:
|
590 | 83dd59c5 | Antony Chazapis | dest_container, dest_name = split_container_object_string(dest_path) |
591 | 83dd59c5 | Antony Chazapis | except ValueError: |
592 | 83dd59c5 | Antony Chazapis | raise BadRequest('Invalid Destination header') |
593 | 83dd59c5 | Antony Chazapis | copy_or_move_object(request, v_account, v_container, v_object, dest_container, dest_name, move=True)
|
594 | b956618e | Antony Chazapis | return HttpResponse(status=201) |
595 | b956618e | Antony Chazapis | |
596 | b956618e | Antony Chazapis | @api_method('POST') |
597 | b956618e | Antony Chazapis | def object_update(request, v_account, v_container, v_object): |
598 | e9285524 | Antony Chazapis | # Normal Response Codes: 202, 204
|
599 | b956618e | Antony Chazapis | # Error Response Codes: serviceUnavailable (503),
|
600 | 3436eeb0 | Antony Chazapis | # conflict (409),
|
601 | b956618e | Antony Chazapis | # itemNotFound (404),
|
602 | b956618e | Antony Chazapis | # unauthorized (401),
|
603 | b956618e | Antony Chazapis | # badRequest (400)
|
604 | b956618e | Antony Chazapis | |
605 | b956618e | Antony Chazapis | meta = get_object_meta(request) |
606 | 3436eeb0 | Antony Chazapis | permissions = get_sharing(request) |
607 | 22dab079 | Antony Chazapis | content_type = meta.get('Content-Type')
|
608 | 22dab079 | Antony Chazapis | if content_type:
|
609 | b956618e | Antony Chazapis | del(meta['Content-Type']) # Do not allow changing the Content-Type. |
610 | 22dab079 | Antony Chazapis | |
611 | cfe6939d | Antony Chazapis | try:
|
612 | 83dd59c5 | Antony Chazapis | prev_meta = backend.get_object_meta(request.user, v_account, v_container, v_object) |
613 | cfe6939d | Antony Chazapis | except NameError: |
614 | cfe6939d | Antony Chazapis | raise ItemNotFound('Object does not exist') |
615 | cfe6939d | Antony Chazapis | |
616 | cfe6939d | Antony Chazapis | # Handle metadata changes.
|
617 | 22dab079 | Antony Chazapis | if len(meta) != 0: |
618 | 22dab079 | Antony Chazapis | # Keep previous values of 'Content-Type' and 'hash'.
|
619 | 22dab079 | Antony Chazapis | for k in ('Content-Type', 'hash'): |
620 | 22dab079 | Antony Chazapis | if k in prev_meta: |
621 | 22dab079 | Antony Chazapis | meta[k] = prev_meta[k] |
622 | 22dab079 | Antony Chazapis | try:
|
623 | 83dd59c5 | Antony Chazapis | backend.update_object_meta(request.user, v_account, v_container, v_object, meta, replace=True)
|
624 | 22dab079 | Antony Chazapis | except NameError: |
625 | 22dab079 | Antony Chazapis | raise ItemNotFound('Object does not exist') |
626 | 22dab079 | Antony Chazapis | |
627 | 3436eeb0 | Antony Chazapis | # Handle permission changes.
|
628 | 3436eeb0 | Antony Chazapis | if permissions:
|
629 | 3436eeb0 | Antony Chazapis | try:
|
630 | 3436eeb0 | Antony Chazapis | backend.update_object_permissions(request.user, v_account, v_container, v_object, permissions) |
631 | 3436eeb0 | Antony Chazapis | except NameError: |
632 | 3436eeb0 | Antony Chazapis | raise ItemNotFound('Object does not exist') |
633 | 3436eeb0 | Antony Chazapis | except ValueError: |
634 | 3436eeb0 | Antony Chazapis | raise BadRequest('Invalid sharing header') |
635 | 3436eeb0 | Antony Chazapis | except AttributeError: |
636 | 3436eeb0 | Antony Chazapis | raise Conflict('Sharing already set above or below this path in the hierarchy') |
637 | 3436eeb0 | Antony Chazapis | |
638 | 3436eeb0 | Antony Chazapis | # TODO: Merge above functions with updating the hashmap if there is data in the request.
|
639 | 3436eeb0 | Antony Chazapis | |
640 | cfe6939d | Antony Chazapis | # A Content-Type or Content-Range header may indicate data updates.
|
641 | 288c1d55 | Antony Chazapis | if content_type is None: |
642 | 288c1d55 | Antony Chazapis | return HttpResponse(status=202) |
643 | 288c1d55 | Antony Chazapis | if content_type.startswith('multipart/byteranges'): |
644 | cfe6939d | Antony Chazapis | # TODO: Support multiple update ranges.
|
645 | cfe6939d | Antony Chazapis | return HttpResponse(status=202) |
646 | cfe6939d | Antony Chazapis | # Single range update. Range must be in Content-Range.
|
647 | 22dab079 | Antony Chazapis | # Based on: http://code.google.com/p/gears/wiki/ContentRangePostProposal
|
648 | cfe6939d | Antony Chazapis | # (with the addition that '*' is allowed for the range - will append).
|
649 | 288c1d55 | Antony Chazapis | if content_type != 'application/octet-stream': |
650 | cfe6939d | Antony Chazapis | return HttpResponse(status=202) |
651 | 22dab079 | Antony Chazapis | content_range = request.META.get('HTTP_CONTENT_RANGE')
|
652 | 22dab079 | Antony Chazapis | if not content_range: |
653 | 22dab079 | Antony Chazapis | return HttpResponse(status=202) |
654 | 22dab079 | Antony Chazapis | ranges = get_content_range(request) |
655 | 22dab079 | Antony Chazapis | if not ranges: |
656 | 22dab079 | Antony Chazapis | return HttpResponse(status=202) |
657 | cfe6939d | Antony Chazapis | # Require either a Content-Length, or 'chunked' Transfer-Encoding.
|
658 | cfe6939d | Antony Chazapis | content_length = -1
|
659 | cfe6939d | Antony Chazapis | if request.META.get('HTTP_TRANSFER_ENCODING') != 'chunked': |
660 | cfe6939d | Antony Chazapis | content_length = get_content_length(request) |
661 | 22dab079 | Antony Chazapis | |
662 | cfe6939d | Antony Chazapis | try:
|
663 | 83dd59c5 | Antony Chazapis | size, hashmap = backend.get_object_hashmap(request.user, v_account, v_container, v_object) |
664 | cfe6939d | Antony Chazapis | except NameError: |
665 | cfe6939d | Antony Chazapis | raise ItemNotFound('Object does not exist') |
666 | cfe6939d | Antony Chazapis | |
667 | cfe6939d | Antony Chazapis | offset, length, total = ranges |
668 | cfe6939d | Antony Chazapis | if offset is None: |
669 | cfe6939d | Antony Chazapis | offset = size |
670 | cb146cf9 | Antony Chazapis | elif offset > size:
|
671 | cb146cf9 | Antony Chazapis | raise RangeNotSatisfiable('Supplied offset is beyond object limits') |
672 | 9a7f747a | Sofia Papagiannaki | if length is None or content_length == -1: |
673 | cfe6939d | Antony Chazapis | length = content_length # Nevermind the error.
|
674 | cfe6939d | Antony Chazapis | elif length != content_length:
|
675 | cfe6939d | Antony Chazapis | raise BadRequest('Content length does not match range length') |
676 | cfe6939d | Antony Chazapis | if total is not None and (total != size or offset >= size or (length > 0 and offset + length >= size)): |
677 | cfe6939d | Antony Chazapis | raise RangeNotSatisfiable('Supplied range will change provided object limits') |
678 | cfe6939d | Antony Chazapis | |
679 | cfe6939d | Antony Chazapis | sock = raw_input_socket(request) |
680 | cfe6939d | Antony Chazapis | data = ''
|
681 | cfe6939d | Antony Chazapis | for d in socket_read_iterator(sock, length, backend.block_size): |
682 | cfe6939d | Antony Chazapis | # TODO: Raise 408 (Request Timeout) if this takes too long.
|
683 | cfe6939d | Antony Chazapis | # TODO: Raise 499 (Client Disconnect) if a length is defined and we stop before getting this much data.
|
684 | cfe6939d | Antony Chazapis | data += d |
685 | cb146cf9 | Antony Chazapis | bytes = put_object_block(hashmap, data, offset) |
686 | cb146cf9 | Antony Chazapis | offset += bytes
|
687 | cb146cf9 | Antony Chazapis | data = data[bytes:]
|
688 | cfe6939d | Antony Chazapis | if len(data) > 0: |
689 | cb146cf9 | Antony Chazapis | put_object_block(hashmap, data, offset) |
690 | cfe6939d | Antony Chazapis | |
691 | cfe6939d | Antony Chazapis | if offset > size:
|
692 | cfe6939d | Antony Chazapis | size = offset |
693 | 83dd59c5 | Antony Chazapis | meta = {'hash': hashmap_hash(hashmap)} # Update ETag. |
694 | cfe6939d | Antony Chazapis | try:
|
695 | 83dd59c5 | Antony Chazapis | backend.update_object_hashmap(request.user, v_account, v_container, v_object, size, hashmap, meta, False)
|
696 | cfe6939d | Antony Chazapis | except NameError: |
697 | cfe6939d | Antony Chazapis | raise ItemNotFound('Container does not exist') |
698 | 3436eeb0 | Antony Chazapis | except ValueError: |
699 | 3436eeb0 | Antony Chazapis | raise BadRequest('Invalid sharing header') |
700 | 3436eeb0 | Antony Chazapis | except AttributeError: |
701 | 3436eeb0 | Antony Chazapis | raise Conflict('Sharing already set above or below this path in the hierarchy') |
702 | 3436eeb0 | Antony Chazapis | |
703 | e9285524 | Antony Chazapis | response = HttpResponse(status=204)
|
704 | e9285524 | Antony Chazapis | response['ETag'] = meta['hash'] |
705 | e9285524 | Antony Chazapis | return response
|
706 | b956618e | Antony Chazapis | |
707 | b956618e | Antony Chazapis | @api_method('DELETE') |
708 | b956618e | Antony Chazapis | def object_delete(request, v_account, v_container, v_object): |
709 | b956618e | Antony Chazapis | # Normal Response Codes: 204
|
710 | b956618e | Antony Chazapis | # Error Response Codes: serviceUnavailable (503),
|
711 | b956618e | Antony Chazapis | # itemNotFound (404),
|
712 | b956618e | Antony Chazapis | # unauthorized (401),
|
713 | b956618e | Antony Chazapis | # badRequest (400)
|
714 | b956618e | Antony Chazapis | |
715 | b956618e | Antony Chazapis | try:
|
716 | 83dd59c5 | Antony Chazapis | backend.delete_object(request.user, v_account, v_container, v_object) |
717 | b956618e | Antony Chazapis | except NameError: |
718 | b956618e | Antony Chazapis | raise ItemNotFound('Object does not exist') |
719 | b956618e | Antony Chazapis | return HttpResponse(status=204) |
720 | b956618e | Antony Chazapis | |
721 | b956618e | Antony Chazapis | @api_method()
|
722 | b956618e | Antony Chazapis | def method_not_allowed(request): |
723 | b956618e | Antony Chazapis | raise BadRequest('Method not allowed') |