Package httxlib :: Module httxresponse
[hide private]
[frames] | no frames]

Source Code for Module httxlib.httxresponse

  1  #!/usr/bin/env python 
  2  # -*- coding: latin-1; py-indent-offset:4 -*- 
  3  ################################################################################ 
  4  #  
  5  # This file is part of HttxLib 
  6  # 
  7  # HttxLib is an HTTP(s) Python library suited multithreaded/multidomain 
  8  # applications 
  9  # 
 10  # Copyright (C) 2010-2011 Daniel Rodriguez (aka Daniel Rodriksson) 
 11  # Copyright (C) 2011 Sensible Odds Ltd 
 12  # 
 13  # You can learn more and contact the author at: 
 14  # 
 15  #    http://code.google.com/p/httxlib/ 
 16  # 
 17  # HttxLib is free software: you can redistribute it and/or modify 
 18  # it under the terms of the GNU General Public License as published by 
 19  # the Free Software Foundation, either version 3 of the License, or 
 20  # (at your option) any later version. 
 21  # 
 22  # HttxLib is distributed in the hope that it will be useful, 
 23  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 24  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 25  # GNU General Public License for more details. 
 26  # 
 27  # You should have received a copy of the GNU General Public License 
 28  # along with HttxLib. If not, see <http://www.gnu.org/licenses/>. 
 29  # 
 30  ################################################################################ 
 31  ''' 
 32  This module implements a series of hacks to the HTTPResponse class to enable 
 33  extra functionaliy (and practical in some cases) for the HttxLib 
 34   
 35  Rather than creating a new class and given that HTTPResponse is already well 
 36  suited for usage in CookieJars (except for the missing info method), extending 
 37  the class seems suitable. 
 38   
 39  Subclassing is not possible, because the HTTPResponse is instantiated inside 
 40  httplib. 
 41   
 42  Creating a class and instantiating it out of the data stored in the HTTPResponse 
 43  would be possible but data would have to be copied for each response. 
 44   
 45  This alternative seems the better: patching the class definition at the start of 
 46  the program and therefore be able to use the instantiated HTTPResponse everywhere 
 47  ''' 
 48   
 49  from cStringIO import StringIO 
 50  from httplib import HTTPResponse 
 51   
 52   
53 -def httxinit(self, sock, debuglevel=0, strict=0, method=None):
54 ''' 55 It replaces the HTTPResponse.__init__ to allow to add and initialize 56 a member variable at object instantiation 57 58 Sock is the opaque type (actually a Python sock object) used in HttxLib 59 to index connecting objects with pending network activity 60 ''' 61 self._httxinit(sock, debuglevel=debuglevel, strict=strict, method=method) 62 self.sock = None
63 64 HTTPResponse._httxinit = HTTPResponse.__init__ 65 HTTPResponse.__init__ = httxinit 66 67
68 -def httxredirecting_or_authenticating(self):
69 ''' 70 Utility function to check if a response is underdoing a redirection 71 or authentication and network activity is pending redirection or a 72 CONNECT tunnel has been initiated 73 74 @return: if the response is underdoing a redirection or authentication 75 and network activity is pending 76 @rtype: bool 77 ''' 78 return self.redirecting() or self.authenticating() or hasattr(self, 'tunnelreq')
79
80 -def httxisredir(self):
81 ''' 82 Utility function to check if a response is requesting redirection 83 84 @return: if the response is a request to redirect 85 @rtype: bool 86 ''' 87 return self.status in (301, 302, 303, 307)
88
89 -def httxisredirget(self):
90 ''' 91 Utility function to check if the redir codes are good for a GET request 92 93 @return: if the redir codes are good for a GET request 94 @rtype: bool 95 ''' 96 return self.status in (301, 302, 303, 307)
97
98 -def httxisredirpost(self):
99 ''' 100 Utility function to check if the redir codes are good for a POST request 101 102 @return: if the redir codes are good for a POST request 103 @rtype: bool 104 ''' 105 return self.status in (301, 302, 303)
106
107 -def httxisredirpostrfc2616(self):
108 ''' 109 Utility function to check if the redir codes are good for a POST request 110 according to RFC 2616 111 112 @return: if the redir codes are good for a POST request 113 according to RFC 2616 114 @rtype: bool 115 ''' 116 return self.status in (301, 302)
117
118 -def httxisauth(self):
119 ''' 120 Utility function to check if a response is requesting authentication 121 122 @return: if a response is requesting authentication 123 @rtype: bool 124 ''' 125 return self.status in (401, 407)
126
127 -def httxredirecting(self):
128 ''' 129 Utility function to check if a response indicates that pending network 130 activity exists, because a new request has been isssued following a 131 redirect request 132 133 @return: if a response is undergoing network activity because a 134 redirection request has been sent 135 @rtype: bool 136 ''' 137 return self.sock and self.isredir()
138
139 -def httxauthenticating(self):
140 ''' 141 Utility function to check if a response indicates that pending network 142 activity exists, because a new request has been isssued following an 143 authentication request 144 145 @return: if a response is undergoing network activity because an 146 authentication request has been sent 147 @rtype: bool 148 ''' 149 return self.sock and self.isauth()
150
151 -def httxisauthuser(self):
152 ''' 153 Utility function to check if the requested authentication is www-authenticate 154 155 @return: if the requested authentication is www-authenticate 156 @rtype: bool 157 ''' 158 return self.status == 401
159
160 -def httxisauthproxy(self):
161 ''' 162 Utility function to check if the requested authentication is proxy-authenticate 163 164 @return: if the requested authentication is proxy-authenticate 165 @rtype: bool 166 ''' 167 return self.status == 407
168 169 170 HTTPResponse.redirecting = httxredirecting 171 HTTPResponse.authenticating = httxauthenticating 172 HTTPResponse.isauthuser = httxisauthuser 173 HTTPResponse.isauthproxy = httxisauthproxy 174 HTTPResponse.redirecting_or_authenticating = httxredirecting_or_authenticating 175 HTTPResponse.isactive = httxredirecting_or_authenticating 176 HTTPResponse.isauth = httxisauth 177 HTTPResponse.isredir = httxisredir 178 HTTPResponse.isredirget = httxisredirget 179 HTTPResponse.isredirpost = httxisredirpost 180 HTTPResponse.isredirpostrfc2616 = httxisredirpostrfc2616 181
182 -def httxinfo(self):
183 ''' 184 Utility function to make HTTPResponse fully compatible with CookieJar requirements 185 186 @return: the message object from HTTPResponse 187 @rtype: HTTPMessage 188 ''' 189 return self.msg
190 191 HTTPResponse.info = httxinfo 192 193
194 -def httxbegin(self):
195 ''' 196 Wrapper for HTTPResponse.begin to allow for the body to be read and leave the 197 connection free for further re-use 198 ''' 199 # HTTPResponse will return if self.msg has been filled with 200 # an object. In such a case we will already have performed 201 # a read and have a body attribute available for us 202 # If not needed, de-activate the code below 203 if self.msg is not None: 204 return 205 206 # Call the original begin method 207 self._httxbegin() 208 209 # Response will close the connection with a the flawed logic seen below if not chunked and no length 210 # This kills "CONNECT" connections and it is not logic to kill a connection simply because 211 # it has no content (202 doesn't usually carry content and 204 is NO_CONTENT) 212 # 213 # if not self.will_close and not self.chunked and self.length is None: 214 # self.will_close = 1 215 216 # Redo the check with the appropriate logic 217 self.will_close = self._check_close() 218 219 # Fill the body with all the content in which will set this 220 # response as "closed" (just the response, no the connection) 221 # Call the original read method 222 if not self.will_close and (self.chunked or self.length): 223 self.setbody(self._httxread()) 224 else: 225 # set an empty body 226 self.setbody('')
227 228 229 HTTPResponse._httxbegin = HTTPResponse.begin 230 HTTPResponse.begin = httxbegin 231
232 -def httxread(self, amt=None):
233 ''' 234 Wrapper for HTTPResponse.read to read the body contents from the 235 StringIO object created during httxbegin 236 connection free for further re-use 237 238 @param amt: amount of bytes to be read 239 @type amt: int or None 240 @return: the read bytes 241 @rtype: str 242 ''' 243 # the read method should never be called before begin 244 # we assume that begin has been called and therefore we 245 # have our file-like object created 246 return self._httxbodyfile.read(amt)
247 248 HTTPResponse._httxread = HTTPResponse.read 249 HTTPResponse.read = httxread 250 251 # Property alias to manage the body and the creation of the 252 # body file object
253 -def httxgetbody(self):
254 ''' 255 Utility function for a property get descriptor for body 256 257 @return: the body of the http response 258 @rtype: str 259 ''' 260 return self._httxbody
261
262 -def httxsetbody(self, value):
263 ''' 264 Utility function for a property set descriptor for body 265 266 @param value: the body of the http response to set 267 @type value: str 268 ''' 269 self._httxbody = value 270 self._httxbodyfile = StringIO(self._httxbody)
271 272 HTTPResponse.getbody = httxgetbody 273 HTTPResponse.setbody = httxsetbody 274 HTTPResponse.body = property(HTTPResponse.getbody, HTTPResponse.setbody) 275 276 277 # Alias to get the body file object
278 -def httxgetbodyfile(self):
279 ''' 280 Utility function for a property tet descriptor for bodyfile 281 ''' 282 return self._httxbodyfile
283 284 HTTPResponse.getbodyfile = httxgetbodyfile 285 HTTPResponse.bodyfile = property(HTTPResponse.getbodyfile) 286 287 # Property alias 288 HTTPResponse.headers = property(HTTPResponse.getheaders) 289
290 -def _httxgetheaderlist(self, name):
291 ''' 292 return a list of all header returned with the same name 293 (www-authenticate is an example) 294 295 @param name: name of the header 296 @type name: str 297 298 @return: a list of the values sent for the header 299 @rtype: list 300 ''' 301 if self.msg is None: 302 raise ResponseNotReady() 303 return self.msg.getheaders(name)
304 305 # Alias 306 HTTPResponse.getheaderlist = _httxgetheaderlist 307 308 # Make a class alias 309 HttxResponse = HTTPResponse 310