Pool connections
[kamaki] / kamaki / clients / connection / kamakicon.py
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 . import HTTPConnection, HTTPResponse, HTTPConnectionError
37
38
39 from time import sleep
40 from httplib import ResponseNotReady
41
42 class KamakiHTTPResponse(HTTPResponse):
43
44     def _get_response(self):
45         print('KamakiHTTPResponse:should I get response?')
46         if self.prefetched:
47             print('\tKamakiHTTPResponse: no, I have already done that before')
48             return
49         print('\tKamakiHTTPResponse: yes, pls')
50         r = self.request.getresponse()
51         self.prefetched = True
52         headers = {}
53         for k,v in r.getheaders():
54             headers.update({k:v})
55         self.headers = headers
56         self.content = r.read(r.length)
57         self.status_code = r.status
58         self.status = r.reason
59         print('KamakiHTTPResponse: Niiiiice')
60
61     @property 
62     def text(self):
63         _get_response()
64         return self._content
65     @text.setter
66     def test(self, v):
67         pass
68
69     @property 
70     def json(self):
71         _get_response()
72         from json import loads
73         try:
74             return loads(self._content)
75         except ValueError as err:
76             HTTPConnectionError('Response not formated in JSON', details=unicode(err), status=702)
77     @json.setter
78     def json(self, v):
79         pass
80
81 class KamakiHTTPConnection(HTTPConnection):
82
83     url         =   None
84     scheme      =   None
85     netloc      =   None
86     method      =   None
87     data        =   None
88     headers     =   None
89
90     scheme_ports = {
91             'http':     '80',
92             'https':    '443',
93     }
94
95     def _load_connection_settings(self, url=None, scheme=None, params=None, headers=None, host=None,
96         port=None, method=None):
97         if params is not None:
98             self.params = params
99         if headers is not None:
100             self.headers = headers
101
102         if url is None:
103             url = self.url
104         if host is None or scheme is None:
105             p = urlparse(url)
106             netloc = p.netloc
107             if not netloc:
108                 netloc = 'localhost'
109             scheme = p.scheme
110             if not scheme:
111                 scheme = 'http'
112             param_str = ''
113             for i,(key, val) in enumerate(self.params.items()):
114                 param_str = ('?' if i == 0 else '&') + unicode(key) 
115                 if val is not None:
116                     param_str+= '='+unicode(val)
117             url = p.path + param_str
118         else:
119             host = host
120             port = port if port is not None else self.scheme_ports[scheme]
121             #NOTE: we force host:port as canonical form,
122             #      lest we have a cache miss 'host' vs 'host:80'
123             netloc = "%s%s" % (host, port)
124
125         self.netloc = netloc
126         self.url = url #if url in (None, '') or url[0] != '/' else url[1:]
127         self.scheme = scheme
128
129         if method is not None:
130             self.method = method
131
132     def perform_request(self, url=None, params=None, headers=None, method=None, host=None,
133         port=None, data=None):
134         self._load_connection_settings(url=url, params=params, headers=headers, host=host,
135             port=port, method=method)
136         print('---> %s %s %s %s %s'%(self.method, self.scheme, self.netloc, self.url, self.headers))
137         conn = get_http_connection(netloc=self.netloc, scheme=self.scheme)
138         try:
139             conn.request(self.method, self.url, headers=self.headers, body=data)
140         except:
141             conn.close()
142             raise
143         return KamakiHTTPResponse(conn)