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

Source Code for Module httxlib.httxmanager

  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  Main connecting object L{HttxManager} implementation 
 33  ''' 
 34   
 35  from httxbase import HttxBase 
 36  from httxnetlocation import HttxNetLocation 
 37  import httxoptions 
 38   
 39   
40 -class HttxManager(HttxBase):
41 ''' 42 Main HttxLib Connecting object. The HttxManager is responsible for creating 43 and managing a set of L{HttxNetLocation} (net locations) objects that will in 44 turn hold the actual connections. 45 46 The net location objects will be created on demand and kept in storage. 47 A reference to active netlocations, (those with a pending L{getresponse} 48 after a L{request}) will also be stored in a cache. 49 50 @ivar options: The shared options for the connection(s) 51 @type options: L{HttxOptions} 52 ''' 53
54 - def __init__(self, **kwargs):
55 ''' 56 Constructor. It delegates construction to the base class 57 HttxBase, except for the proxy that will be set specifically 58 59 Setting the proxy ensures the initialization of the storage of 60 netlocations and the cache of active netlocations 61 62 @param kwargs: keywords arguments 63 @see: L{HttxOptions} 64 ''' 65 HttxBase.__init__(self, **kwargs) 66 self.netlocations = dict() 67 self.locationcache = dict() 68 69 if httxoptions.proxydefaults: 70 self.setproxydefaults() 71 72 # The user may have enforced a private proxy for a particular protocol 73 # not necessarily overriding all system proxies (or yes) 74 if 'proxy' in kwargs: 75 self.setproxy(kwargs['proxy'])
76 77
78 - def __deepcopy__(self, memo):
79 ''' 80 Deepcopy support. 81 82 @param memo: standard __deepcopy__ parameter to avoid circular references 83 @type memo: dict 84 @return: cloned object 85 @rtype: L{HttxManager} 86 @see L{clone} 87 ''' 88 return self.clone()
89 90
91 - def clone(self, options=None, netLocations=True):
92 ''' 93 Clone the object using the supplied options or a new set of options if 94 given. 95 96 An equivalente set of L{HttxNetLocation} net locations will be replicated 97 98 A new set of options will separate the clone object from the original 99 object, since they will no longer share cookies, user/password/realm 100 combinations or https certificates 101 102 @param options: options for the cloned object 103 @type options: L{HttxOptions} 104 @param netLocations: whether to clone the existing netlocations 105 @type netLocations: bool 106 @return: cloned object 107 @rtype: L{HttxManager} 108 ''' 109 if not options: 110 options = self.options.clone() 111 112 clone = self.__class__(options=options) 113 114 # Replicate the existing set of netlocations 115 if netLocations: 116 with self.lock: 117 for netlockey, netlocation in self.netlocations.iteritems(): 118 clone.netlocations[netlockey] = netlocation.clone(options=options) 119 120 return clone
121 122
123 - def setproxydefaults(self):
124 ''' 125 Set the proxy options from OS defaults or environment variables if present using 126 the functionality preset in urllib 127 ''' 128 from urllib import getproxies 129 from urlparse import urlsplit 130 proxies = getproxies() 131 132 # Windows will return the "https" proxy with an "https" scheme when all protocols 133 # should be using the same proxy. But obviously the same netlocation is not 134 # simultaneously listening for clean and encrypted connections 135 http = proxies.get('http', None) 136 if http is not None: 137 https = proxies.get('https', None) 138 if https is not None: 139 httpparsed = urlsplit(http) 140 httpsparsed = urlsplit(https) 141 if httpparsed.netloc == httpparsed.netloc: 142 proxies['https'] = http 143 144 self.setproxy(proxies)
145 146
147 - def setproxy(self, proxy=None):
148 ''' 149 Set the proxy options by opening specific netlocations for http and/or https schemes 150 The proxy can be different for http and https connections. 151 152 The L{HttxNetLocation} net locations storage and cache of active net locations 153 are initialized 154 155 @param proxy: proxy servers. Dictionary with scheme:url pairs. 156 '*' or 'httx' as the scheme stands for both http and https 157 @type proxy: dict 158 ''' 159 with self.lock: 160 self.netlocations = dict() 161 self.locationcache = dict() 162 163 if proxy: 164 if '*' in proxy: 165 proxy = {'http': proxy['*'], 'https': proxy['*']} 166 elif 'httpx' in proxy: 167 proxy = {'http': proxy['httpx'], 'https': proxy['httpx']} 168 169 for scheme, url in proxy.iteritems(): 170 self.netlocations[scheme] = HttxNetLocation(url, options=self.options)
171 172
173 - def _getnetlocation(self, httxreq):
174 ''' 175 Internal interface to fetch the appropiate L{HttxNetLocation} net location object 176 to use to issue a request as specified by httxreq 177 178 @param httxreq: Request to be executed 179 @type httxreq: L{HttxRequest} 180 @return: httxnetlocation 181 @rtype: L{HttxNetLocation} 182 ''' 183 # Protected to avoid a change of proxy options 184 with self.lock: 185 if httxreq.scheme == 'http' and 'http' in self.netlocations: 186 # http request and http proxy in place 187 httxnetlocation = self.netlocations[httxreq.scheme] 188 elif httxreq.scheme == 'https' and 'https' in self.netlocations: 189 # https request and http proxy in place 190 httxnetlocation = self.netlocations[httxreq.scheme] 191 if self.options.httpsconnect: 192 # connect is requested. each "https netloc" must have its own httxnetlocation 193 # create a new netlocation with the original https proxy url 194 # or fetch and existing one for the netlocation 195 httxnetlocation = self.netlocations.setdefault(httxreq.netloc, 196 HttxNetLocation(httxnetlocation.url, 197 options=self.options)) 198 else: 199 # Regular direct connection 200 httxnetlocation = self.netlocations.setdefault(httxreq.netloc, 201 HttxNetLocation(httxreq.get_full_url(), 202 options=self.options)) 203 204 # netlocation fetched - it can be given to different threads because it is also thread-safe 205 return httxnetlocation
206 207
208 - def request(self, httxreq):
209 ''' 210 Send the L{HttxRequest} httxreq to the specified server inside the request 211 212 @param httxreq: Request or url to be executed 213 @type httxreq: L{HttxRequest} or url (string) 214 @return: sock 215 @rtype: opaque type for the caller (a Python sock) 216 ''' 217 httxnetlocation = self._getnetlocation(httxreq) 218 sock = httxnetlocation.request(httxreq) 219 220 # Store the sock - location relationship in a dictionary 221 with self.lock: 222 self.locationcache[sock] = httxnetlocation 223 224 return sock
225 226
227 - def getresponse(self, sock):
228 ''' 229 Recover a L{HttxResponse} using a net location from the cache of 230 active L{HttxNetLocation} net locations and calling its getresponse 231 232 @param sock: The opaque type returned by L{request} 233 @type sock: opaque (a Python sock) 234 @return: response 235 @rtype: L{HttxResponse} (compatible with httplib HTTPResponse) 236 ''' 237 with self.lock: 238 # Get net location out of the cache of active net locations 239 httxnetlocation = self.locationcache.pop(sock) 240 241 # get the actual response 242 response = httxnetlocation.getresponse(sock) 243 244 # Check if the response is active (authenticating or redirecting) 245 if response.isactive(): 246 # The response is undergoing further network activity 247 # Place it again (with the returned sock which may be new) 248 # in the cache of active locations 249 with self.lock: 250 self.locationcache[response.sock] = httxnetlocation 251 252 return response
253