Use connection pool after redesigning http connect
[kamaki] / kamaki / clients / connection / __init__.py
1 # Copyright 2011-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 .pool import ObjectPool
35
36 POOL_SIZE=8
37
38 class HTTPResponsePool(ObjectPool):
39
40     def __init__(self, netloc, size=POOL_SIZE):
41         super(HTTPResponsePool, self).__init__(size=size)
42         self.netloc = netloc
43
44     def _pool_create(self):
45         resp = HTTPResponse()
46         resp._pool = self
47         return resp
48
49     def _pool_cleanup(self, resp):
50         resp._get_response()
51         return True
52
53 class HTTPResponse(object):
54
55     def __init__(self, request=None, prefetched=False):
56         self.request=request
57         if prefetched:
58             self = request.response
59         self.prefetched = prefetched
60
61     def _get_response(self):
62         """Wait for http response as late as possible: the first time needed"""
63         if self.prefetched:
64             return
65         self = self.request.response
66         self.prefetched = True
67
68     def release(self):
69         """Release the connection.
70         Use this after finished using the response"""
71         raise NotImplementedError
72
73     @property 
74     def prefetched(self):
75         return self._prefetched
76     @prefetched.setter
77     def prefetched(self, p):
78         self._prefetched = p
79
80     @property 
81     def content(self):
82         self._get_response()
83         return self._content
84     @content.setter 
85     def content(self, v):
86         self._content = v
87
88     @property 
89     def text(self):
90         self._get_response()
91         return self._text
92     @text.setter 
93     def text(self, v):
94         self._text = v
95
96     @property 
97     def json(self):
98         self._get_response()
99         return self._json
100     @json.setter 
101     def json(self, v):
102         self._json = v
103
104     @property 
105     def headers(self):
106         self._get_response()
107         return self._headers
108     @headers.setter 
109     def headers(self, v):
110         self._headers = v
111
112     @property 
113     def status_code(self):
114         self._get_response()
115         return self._status_code
116     @status_code.setter 
117     def status_code(self, v):
118         self._status_code = v
119
120     @property 
121     def status(self):
122         self._get_response()
123         return self._status
124     @status.setter 
125     def status(self, v):
126         self._status = v
127
128     @property 
129     def request(self):
130         return self._request
131     @request.setter 
132     def request(self, v):
133         self._request = v
134
135 class HTTPConnectionError(Exception):
136     def __init__(self, message, status=0, details=''):
137         super(HTTPConnectionError, self).__init__(message)
138         self.message = message
139         self.status = status
140         self.details = details
141
142 class HTTPConnection(object):
143
144     def __init__(self, method=None, url=None, params={}, headers={}):
145         self.headers = headers
146         self.params = params
147         self.url = url
148         self.method = method
149
150     def raise_for_status(self, r):
151         message = "%d %s" % (r.status_code, r.status)
152         try:
153             details = r.text
154         except:
155             details = ''
156         raise HTTPConnectionError(message, r.status_code, details)
157
158     def set_header(self, name, value):
159         self.headers[unicode(name)] = unicode(value)
160
161     def remove_header(self, name):
162         try:
163                 self.headers.pop(name)
164         except KeyError:
165                 pass
166
167     def replace_headers(self, new_headers):
168         self.headers = new_headers
169
170     def reset_headers(self):
171         self.replace_headers({})
172
173     def set_param(self, name, value=None):
174         self.params[name] = value
175
176     def remove_param(self, name):
177         try:
178                 self.params.pop(name)
179         except KeyError:
180                 pass
181
182     def replace_params(self, new_params):
183         self.params = new_params
184
185     def reset_params(self):
186         self.replace_params({})
187
188     def set_url(self, url):
189         self.url = url
190
191     def set_method(self, method):
192         self.method = method
193
194         def perform_request(self, method=None, url=None, params=None, headers=None, data=None):
195                 """
196                 @return an HTTPResponse (also in self.response of this object)
197                 named args offer the ability to reset a request or a part of the request
198                 e.g. r = HTTPConnection(url='http://....', method='GET')
199                          r.perform_request()
200                          r.perform_request(method='POST')
201                 will perform a GET request and later a POST request on the same URL
202                 another example:
203                          r = HTTPConnection(url='http://....', params='format=json')
204                          r.perform_request(method='GET')
205                          r.perform_request(method='POST')
206                 """
207                 raise NotImplementedError
208
209     """
210     @property 
211     def response(self):
212         return self._response
213     @response.setter
214     def response(self, r):
215         self._response = r
216     """