1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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
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
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
73
74 if 'proxy' in kwargs:
75 self.setproxy(kwargs['proxy'])
76
77
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
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
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
133
134
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
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
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
184 with self.lock:
185 if httxreq.scheme == 'http' and 'http' in self.netlocations:
186
187 httxnetlocation = self.netlocations[httxreq.scheme]
188 elif httxreq.scheme == 'https' and 'https' in self.netlocations:
189
190 httxnetlocation = self.netlocations[httxreq.scheme]
191 if self.options.httpsconnect:
192
193
194
195 httxnetlocation = self.netlocations.setdefault(httxreq.netloc,
196 HttxNetLocation(httxnetlocation.url,
197 options=self.options))
198 else:
199
200 httxnetlocation = self.netlocations.setdefault(httxreq.netloc,
201 HttxNetLocation(httxreq.get_full_url(),
202 options=self.options))
203
204
205 return httxnetlocation
206
207
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
221 with self.lock:
222 self.locationcache[sock] = httxnetlocation
223
224 return sock
225
226
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
239 httxnetlocation = self.locationcache.pop(sock)
240
241
242 response = httxnetlocation.getresponse(sock)
243
244
245 if response.isactive():
246
247
248
249 with self.lock:
250 self.locationcache[response.sock] = httxnetlocation
251
252 return response
253