Statistics
| Branch: | Tag: | Revision:

root / kamaki / clients / connection / kamakicon.py @ e02728f9

History | View | Annotate | Download (4.7 kB)

1
# Copyright 2012 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, self.list of conditions and the following
9
#      disclaimer.
10
#
11
#   2. Redistributions in binary form must reproduce the above
12
#      copyright notice, self.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
from urlparse import urlparse
35
#from .pool.http import get_http_connection
36
from synnefo.lib.pool.http import get_http_connection
37
from kamaki.clients.connection import HTTPConnection, HTTPResponse,\
38
    HTTPConnectionError
39
from socket import gaierror
40

    
41
from json import loads
42

    
43
from time import sleep
44
from httplib import ResponseNotReady
45

    
46

    
47
class KamakiHTTPResponse(HTTPResponse):
48

    
49
    def _get_response(self):
50
        if self.prefetched:
51
            return
52

    
53
        ready = False
54
        while not ready:
55
            try:
56
                r = self.request.getresponse()
57
            except ResponseNotReady:
58
                sleep(0.001)
59
                continue
60
            break
61
        self.prefetched = True
62
        headers = {}
63
        for k, v in r.getheaders():
64
            headers.update({k: v})
65
        self.headers = headers
66
        self.content = r.read()
67
        self.status_code = r.status
68
        self.status = r.reason
69
        self.request.close()
70

    
71
    @property
72
    def text(self):
73
        self._get_response()
74
        return self._content
75

    
76
    @text.setter
77
    def test(self, v):
78
        pass
79

    
80
    @property
81
    def json(self):
82
        self._get_response()
83
        try:
84
            return loads(self._content)
85
        except ValueError as err:
86
            HTTPConnectionError('Response not formated in JSON',
87
                details=unicode(err),
88
                status=702)
89

    
90
    @json.setter
91
    def json(self, v):
92
        pass
93

    
94
    def release(self):
95
        if not self.prefetched:
96
            self.request.close()
97

    
98

    
99
class KamakiHTTPConnection(HTTPConnection):
100

    
101
    def _retrieve_connection_info(self, extra_params={}):
102
        """ return (scheme, netloc, url?with&params) """
103
        url = self.url
104
        params = dict(self.params)
105
        for k, v in extra_params.items():
106
            params[k] = v
107
        for i, (key, val) in enumerate(params.items()):
108
            param_str = ('?' if i == 0 else '&') + unicode(key)
109
            if val is not None:
110
                param_str += '=' + unicode(val)
111
            url += param_str
112

    
113
        parsed = urlparse(self.url)
114
        self.url = url
115
        return (parsed.scheme, parsed.netloc)
116

    
117
    def perform_request(self,
118
        method=None,
119
        data=None,
120
        async_headers={},
121
        async_params={}):
122
        (scheme, netloc) = self._retrieve_connection_info(
123
            extra_params=async_params)
124
        headers = dict(self.headers)
125
        for k, v in async_headers.items():
126
            headers[k] = v
127

    
128
        #de-unicode headers to prepare them for http
129
        http_headers = {}
130
        for k, v in headers.items():
131
            http_headers[str(k)] = str(v)
132

    
133
        #get connection from pool
134
        conn = get_http_connection(netloc=netloc, scheme=scheme)
135
        try:
136
            #Be carefull, all non-body variables should not be unicode
137
            conn.request(method=str(method.upper()),
138
                url=str(self.url),
139
                headers=http_headers,
140
                body=data)
141
        except Exception as err:
142
            conn.close()
143
            if isinstance(err, gaierror):
144
                raise HTTPConnectionError('Cannot connect to %s' % self.url,
145
                    status=701,
146
                    details='%s: %s' % (type(err), unicode(err)))
147
            raise
148
        return KamakiHTTPResponse(conn)