Statistics
| Branch: | Tag: | Revision:

root / pithos / public / functions.py @ 2c22e4ac

History | View | Annotate | Download (5.3 kB)

1
# Copyright 2011 GRNET S.A. All rights reserved.
2
# 
3
# Redistribution and use in source and binary forms, with or
4
# without modification, are permitted provided that the following
5
# conditions are met:
6
# 
7
#   1. Redistributions of source code must retain the above
8
#      copyright notice, this list of conditions and the following
9
#      disclaimer.
10
# 
11
#   2. Redistributions in binary form must reproduce the above
12
#      copyright notice, this list of conditions and the following
13
#      disclaimer in the documentation and/or other materials
14
#      provided with the distribution.
15
# 
16
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
# POSSIBILITY OF SUCH DAMAGE.
28
# 
29
# The views and conclusions contained in the software and
30
# documentation are those of the authors and should not be
31
# interpreted as representing official policies, either expressed
32
# or implied, of GRNET S.A.
33

    
34
import logging
35
import uuid
36

    
37
from django.http import HttpResponse
38

    
39
from pithos.api.faults import (Fault, BadRequest, ItemNotFound, RangeNotSatisfiable)
40
from pithos.api.util import (put_object_meta, validate_modification_preconditions,
41
    validate_matching_preconditions, get_range, ObjectWrapper, api_method)
42
from pithos.backends import backend
43

    
44

    
45
logger = logging.getLogger(__name__)
46

    
47

    
48
def object_demux(request, v_account, v_container, v_object):
49
    if request.method == 'HEAD':
50
        return object_meta(request, v_account, v_container, v_object)
51
    elif request.method == 'GET':
52
        return object_read(request, v_account, v_container, v_object)
53
    else:
54
        return method_not_allowed(request)
55

    
56
# TODO: Use a version of api_method that does not check for a token.
57

    
58
@api_method('HEAD')
59
def object_meta(request, v_account, v_container, v_object):
60
    # Normal Response Codes: 204
61
    # Error Response Codes: serviceUnavailable (503),
62
    #                       itemNotFound (404),
63
    #                       unauthorized (401),
64
    #                       badRequest (400)
65
    
66
    try:
67
        meta = backend.get_object_meta(v_account, v_container, v_object)
68
    except NameError:
69
        raise ItemNotFound('Object does not exist')
70
    
71
    if 'X-Object-Public' not in meta:
72
        raise ItemNotFound('Object does not exist')
73
    
74
    response = HttpResponse(status=204)
75
    put_object_meta(response, meta)
76
    return response
77

    
78
@api_method('GET')
79
def object_read(request, v_account, v_container, v_object):
80
    # Normal Response Codes: 200, 206
81
    # Error Response Codes: serviceUnavailable (503),
82
    #                       rangeNotSatisfiable (416),
83
    #                       preconditionFailed (412),
84
    #                       itemNotFound (404),
85
    #                       unauthorized (401),
86
    #                       badRequest (400),
87
    #                       notModified (304)
88
    
89
    try:
90
        meta = backend.get_object_meta(v_account, v_container, v_object)
91
    except NameError:
92
        raise ItemNotFound('Object does not exist')
93
    
94
    if 'X-Object-Public' not in meta:
95
        raise ItemNotFound('Object does not exist')
96
    
97
    # Evaluate conditions.
98
    validate_modification_preconditions(request, meta)
99
    try:
100
        validate_matching_preconditions(request, meta)
101
    except NotModified:
102
        response = HttpResponse(status=304)
103
        response['ETag'] = meta['hash']
104
        return response
105
    
106
    try:
107
        size, hashmap = backend.get_object_hashmap(v_account, v_container, v_object)
108
    except NameError:
109
        raise ItemNotFound('Object does not exist')
110
    
111
    # Range handling.
112
    ranges = get_range(request, size)
113
    if ranges is None:
114
        ranges = [(0, size)]
115
        ret = 200
116
    else:
117
        check = [True for offset, length in ranges if
118
                    length <= 0 or length > size or
119
                    offset < 0 or offset >= size or
120
                    offset + length > size]
121
        if len(check) > 0:
122
            raise RangeNotSatisfiable('Requested range exceeds object limits')        
123
        ret = 206
124
    
125
    if ret == 206 and len(ranges) > 1:
126
        boundary = uuid.uuid4().hex
127
    else:
128
        boundary = ''
129
    wrapper = ObjectWrapper(v_account, v_container, v_object, ranges, size, hashmap, boundary)
130
    response = HttpResponse(wrapper, status=ret)
131
    put_object_meta(response, meta)
132
    if ret == 206:
133
        if len(ranges) == 1:
134
            offset, length = ranges[0]
135
            response['Content-Length'] = length # Update with the correct length.
136
            response['Content-Range'] = 'bytes %d-%d/%d' % (offset, offset + length - 1, size)
137
        else:
138
            del(response['Content-Length'])
139
            response['Content-Type'] = 'multipart/byteranges; boundary=%s' % (boundary,)
140
    return response
141

    
142
@api_method()
143
def method_not_allowed(request):
144
    raise ItemNotFound('Object does not exist')