Statistics
| Branch: | Tag: | Revision:

root / kamaki / clients / connection / kamakicon.py @ 1f417830

History | View | Annotate | Download (6.2 kB)

1 f364f960 Stavros Sachtouris
# Copyright 2012 GRNET S.A. All rights reserved.
2 f364f960 Stavros Sachtouris
#
3 f364f960 Stavros Sachtouris
# Redistribution and use in source and binary forms, with or
4 f364f960 Stavros Sachtouris
# without modification, are permitted provided that the following
5 f364f960 Stavros Sachtouris
# conditions are met:
6 f364f960 Stavros Sachtouris
#
7 f364f960 Stavros Sachtouris
#   1. Redistributions of source code must retain the above
8 f364f960 Stavros Sachtouris
#      copyright notice, self.list of conditions and the following
9 f364f960 Stavros Sachtouris
#      disclaimer.
10 f364f960 Stavros Sachtouris
#
11 f364f960 Stavros Sachtouris
#   2. Redistributions in binary form must reproduce the above
12 f364f960 Stavros Sachtouris
#      copyright notice, self.list of conditions and the following
13 f364f960 Stavros Sachtouris
#      disclaimer in the documentation and/or other materials
14 f364f960 Stavros Sachtouris
#      provided with the distribution.
15 f364f960 Stavros Sachtouris
#
16 f364f960 Stavros Sachtouris
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 f364f960 Stavros Sachtouris
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 f364f960 Stavros Sachtouris
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 f364f960 Stavros Sachtouris
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 f364f960 Stavros Sachtouris
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 f364f960 Stavros Sachtouris
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 f364f960 Stavros Sachtouris
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 f364f960 Stavros Sachtouris
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 f364f960 Stavros Sachtouris
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 f364f960 Stavros Sachtouris
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 f364f960 Stavros Sachtouris
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 f364f960 Stavros Sachtouris
# POSSIBILITY OF SUCH DAMAGE.
28 f364f960 Stavros Sachtouris
#
29 f364f960 Stavros Sachtouris
# The views and conclusions contained in the software and
30 f364f960 Stavros Sachtouris
# documentation are those of the authors and should not be
31 f364f960 Stavros Sachtouris
# interpreted as representing official policies, either expressed
32 f364f960 Stavros Sachtouris
# or implied, of GRNET S.A.
33 f364f960 Stavros Sachtouris
34 f364f960 Stavros Sachtouris
from urlparse import urlparse
35 b98fe305 Dionysis Zindros
from objpool.http import get_http_connection
36 d5eeabc0 Stavros Sachtouris
from kamaki.clients.connection import HTTPConnection, HTTPResponse
37 d5eeabc0 Stavros Sachtouris
from kamaki.clients.connection.errors import HTTPConnectionError
38 0238c167 Stavros Sachtouris
from kamaki.clients.connection.errors import HTTPResponseError
39 f8b42e99 Stavros Sachtouris
from socket import gaierror
40 f364f960 Stavros Sachtouris
41 5b263ba2 Stavros Sachtouris
from json import loads
42 f364f960 Stavros Sachtouris
43 f364f960 Stavros Sachtouris
from time import sleep
44 f364f960 Stavros Sachtouris
from httplib import ResponseNotReady
45 f364f960 Stavros Sachtouris
46 3dabe5d2 Stavros Sachtouris
47 f364f960 Stavros Sachtouris
class KamakiHTTPResponse(HTTPResponse):
48 f364f960 Stavros Sachtouris
49 f364f960 Stavros Sachtouris
    def _get_response(self):
50 f364f960 Stavros Sachtouris
        if self.prefetched:
51 f364f960 Stavros Sachtouris
            return
52 5b263ba2 Stavros Sachtouris
53 5b263ba2 Stavros Sachtouris
        ready = False
54 5b263ba2 Stavros Sachtouris
        while not ready:
55 5b263ba2 Stavros Sachtouris
            try:
56 5b263ba2 Stavros Sachtouris
                r = self.request.getresponse()
57 5b263ba2 Stavros Sachtouris
            except ResponseNotReady:
58 0004301f Stavros Sachtouris
                sleep(0.001)
59 5b263ba2 Stavros Sachtouris
                continue
60 5b263ba2 Stavros Sachtouris
            break
61 f364f960 Stavros Sachtouris
        self.prefetched = True
62 f364f960 Stavros Sachtouris
        headers = {}
63 3dabe5d2 Stavros Sachtouris
        for k, v in r.getheaders():
64 3dabe5d2 Stavros Sachtouris
            headers.update({k: v})
65 f364f960 Stavros Sachtouris
        self.headers = headers
66 0004301f Stavros Sachtouris
        self.content = r.read()
67 f364f960 Stavros Sachtouris
        self.status_code = r.status
68 f364f960 Stavros Sachtouris
        self.status = r.reason
69 5b263ba2 Stavros Sachtouris
        self.request.close()
70 f364f960 Stavros Sachtouris
71 3dabe5d2 Stavros Sachtouris
    @property
72 f364f960 Stavros Sachtouris
    def text(self):
73 b4c8b916 Stavros Sachtouris
        """
74 b4c8b916 Stavros Sachtouris
        :returns: (str) content
75 b4c8b916 Stavros Sachtouris
        """
76 5b263ba2 Stavros Sachtouris
        self._get_response()
77 5f7882af Stavros Sachtouris
        return unicode(self._content)
78 3dabe5d2 Stavros Sachtouris
79 f364f960 Stavros Sachtouris
    @text.setter
80 f364f960 Stavros Sachtouris
    def test(self, v):
81 f364f960 Stavros Sachtouris
        pass
82 f364f960 Stavros Sachtouris
83 3dabe5d2 Stavros Sachtouris
    @property
84 f364f960 Stavros Sachtouris
    def json(self):
85 b4c8b916 Stavros Sachtouris
        """
86 b4c8b916 Stavros Sachtouris
        :returns: (dict) the json-formated content
87 b4c8b916 Stavros Sachtouris

88 b4c8b916 Stavros Sachtouris
        :raises HTTPResponseError: if content is not json formated
89 b4c8b916 Stavros Sachtouris
        """
90 5b263ba2 Stavros Sachtouris
        self._get_response()
91 f364f960 Stavros Sachtouris
        try:
92 f364f960 Stavros Sachtouris
            return loads(self._content)
93 f364f960 Stavros Sachtouris
        except ValueError as err:
94 0238c167 Stavros Sachtouris
            HTTPResponseError('Response not formated in JSON - %s' % err)
95 3dabe5d2 Stavros Sachtouris
96 f364f960 Stavros Sachtouris
    @json.setter
97 f364f960 Stavros Sachtouris
    def json(self, v):
98 f364f960 Stavros Sachtouris
        pass
99 f364f960 Stavros Sachtouris
100 5b263ba2 Stavros Sachtouris
    def release(self):
101 b4c8b916 Stavros Sachtouris
        """ Release the connection. Should always be called if the response
102 b4c8b916 Stavros Sachtouris
        content hasn't been used.
103 b4c8b916 Stavros Sachtouris
        """
104 5b263ba2 Stavros Sachtouris
        if not self.prefetched:
105 5b263ba2 Stavros Sachtouris
            self.request.close()
106 f364f960 Stavros Sachtouris
107 f364f960 Stavros Sachtouris
108 5b263ba2 Stavros Sachtouris
class KamakiHTTPConnection(HTTPConnection):
109 f364f960 Stavros Sachtouris
110 9a7efb0d Stavros Sachtouris
    def _retrieve_connection_info(self, extra_params={}):
111 05208859 Stavros Sachtouris
        """
112 05208859 Stavros Sachtouris
        :param extra_params: (dict) key:val for url parameters
113 05208859 Stavros Sachtouris

114 05208859 Stavros Sachtouris
        :returns: (scheme, netloc, url?with&params)
115 05208859 Stavros Sachtouris
        """
116 7d91734c Stavros Sachtouris
        if self.url:
117 7d91734c Stavros Sachtouris
            url = self.url if self.url[-1] == '/' else (self.url + '/')
118 7d91734c Stavros Sachtouris
        else:
119 7e5415a4 Stavros Sachtouris
            url = 'http://127.0.0.1'
120 7d91734c Stavros Sachtouris
        if self.path:
121 7d91734c Stavros Sachtouris
            url += self.path[1:] if self.path[0] == '/' else self.path
122 0004301f Stavros Sachtouris
        params = dict(self.params)
123 3dabe5d2 Stavros Sachtouris
        for k, v in extra_params.items():
124 9a7efb0d Stavros Sachtouris
            params[k] = v
125 3dabe5d2 Stavros Sachtouris
        for i, (key, val) in enumerate(params.items()):
126 3dabe5d2 Stavros Sachtouris
            param_str = ('?' if i == 0 else '&') + unicode(key)
127 5b263ba2 Stavros Sachtouris
            if val is not None:
128 3dabe5d2 Stavros Sachtouris
                param_str += '=' + unicode(val)
129 5b263ba2 Stavros Sachtouris
            url += param_str
130 f364f960 Stavros Sachtouris
131 7d91734c Stavros Sachtouris
        parsed = urlparse(url)
132 5b263ba2 Stavros Sachtouris
        self.url = url
133 7d91734c Stavros Sachtouris
        self.path = parsed.path if parsed.path else '/'
134 7d91734c Stavros Sachtouris
        self.path += '?%s' % parsed.query if parsed.query else ''
135 5b263ba2 Stavros Sachtouris
        return (parsed.scheme, parsed.netloc)
136 f364f960 Stavros Sachtouris
137 3dabe5d2 Stavros Sachtouris
    def perform_request(self,
138 3dabe5d2 Stavros Sachtouris
        method=None,
139 3dabe5d2 Stavros Sachtouris
        data=None,
140 3dabe5d2 Stavros Sachtouris
        async_headers={},
141 3dabe5d2 Stavros Sachtouris
        async_params={}):
142 5f7882af Stavros Sachtouris
        """
143 5f7882af Stavros Sachtouris
        :param method: (str) http method ('get', 'post', etc.)
144 5f7882af Stavros Sachtouris

145 5f7882af Stavros Sachtouris
        :param data: (binary object)
146 5f7882af Stavros Sachtouris

147 5f7882af Stavros Sachtouris
        :param async_headers: (dict) key:val headers that are used only for one
148 5f7882af Stavros Sachtouris
            request instance as opposed to self.headers, which remain to be
149 5f7882af Stavros Sachtouris
            used by following or parallel requests
150 5f7882af Stavros Sachtouris

151 5f7882af Stavros Sachtouris
        :param async_params: (dict) key:val url parameters that are used only
152 5f7882af Stavros Sachtouris
            for one request instance as opposed to self.params, which remain to
153 5f7882af Stavros Sachtouris
            be used by following or parallel requests
154 5f7882af Stavros Sachtouris

155 5f7882af Stavros Sachtouris
        :returns: (KamakiHTTPResponse) a response object
156 5f7882af Stavros Sachtouris

157 5f7882af Stavros Sachtouris
        :raises HTTPConnectionError: Connection failures
158 5f7882af Stavros Sachtouris
        """
159 3dabe5d2 Stavros Sachtouris
        (scheme, netloc) = self._retrieve_connection_info(
160 3dabe5d2 Stavros Sachtouris
            extra_params=async_params)
161 0004301f Stavros Sachtouris
        headers = dict(self.headers)
162 3dabe5d2 Stavros Sachtouris
        for k, v in async_headers.items():
163 9a7efb0d Stavros Sachtouris
            headers[k] = v
164 3ad34f11 Stavros Sachtouris
165 3ad34f11 Stavros Sachtouris
        #de-unicode headers to prepare them for http
166 3ad34f11 Stavros Sachtouris
        http_headers = {}
167 3dabe5d2 Stavros Sachtouris
        for k, v in headers.items():
168 3ad34f11 Stavros Sachtouris
            http_headers[str(k)] = str(v)
169 3ad34f11 Stavros Sachtouris
170 1785ad41 Stavros Sachtouris
        #get connection from pool
171 1785ad41 Stavros Sachtouris
        conn = get_http_connection(netloc=netloc, scheme=scheme)
172 f364f960 Stavros Sachtouris
        try:
173 3ad34f11 Stavros Sachtouris
            #Be carefull, all non-body variables should not be unicode
174 3dabe5d2 Stavros Sachtouris
            conn.request(method=str(method.upper()),
175 7d91734c Stavros Sachtouris
                url=str(self.path),
176 3ad34f11 Stavros Sachtouris
                headers=http_headers,
177 3ad34f11 Stavros Sachtouris
                body=data)
178 b9d07587 Stavros Sachtouris
        except Exception as err:
179 1f417830 Stavros Sachtouris
            from traceback import format_stack
180 1f417830 Stavros Sachtouris
            from kamaki.clients import recvlog
181 1f417830 Stavros Sachtouris
            recvlog.debug('\n'.join(['%s' % type(err)] + format_stack()))
182 f364f960 Stavros Sachtouris
            conn.close()
183 e02728f9 Stavros Sachtouris
            if isinstance(err, gaierror):
184 7e5415a4 Stavros Sachtouris
                raise HTTPConnectionError(
185 0238c167 Stavros Sachtouris
                    'Cannot connect to %s - %s' % (self.url, err))
186 f364f960 Stavros Sachtouris
            raise
187 f364f960 Stavros Sachtouris
        return KamakiHTTPResponse(conn)