Show More
@@ -7,7 +7,7 b'' | |||
|
7 | 7 | # This software may be used and distributed according to the terms of the |
|
8 | 8 | # GNU General Public License version 2, incorporated herein by reference. |
|
9 | 9 | |
|
10 | import urllib, urllib2, urlparse, httplib, os, re | |
|
10 | import urllib, urllib2, urlparse, httplib, os, re, socket, cStringIO | |
|
11 | 11 | from i18n import _ |
|
12 | 12 | import keepalive, util |
|
13 | 13 | |
@@ -245,18 +245,165 b' def _gen_sendfile(connection):' | |||
|
245 | 245 | connection.send(self, data) |
|
246 | 246 | return _sendfile |
|
247 | 247 | |
|
248 | has_https = hasattr(urllib2, 'HTTPSHandler') | |
|
249 | if has_https: | |
|
250 | try: | |
|
251 | # avoid using deprecated/broken FakeSocket in python 2.6 | |
|
252 | import ssl | |
|
253 | _ssl_wrap_socket = ssl.wrap_socket | |
|
254 | except ImportError: | |
|
255 | def _ssl_wrap_socket(sock, key_file, cert_file): | |
|
256 | ssl = socket.ssl(sock, key_file, cert_file) | |
|
257 | return httplib.FakeSocket(sock, ssl) | |
|
258 | ||
|
248 | 259 | class httpconnection(keepalive.HTTPConnection): |
|
249 | 260 | # must be able to send big bundle as stream. |
|
250 | 261 | send = _gen_sendfile(keepalive.HTTPConnection) |
|
251 | 262 | |
|
263 | def _proxytunnel(self): | |
|
264 | proxyheaders = dict( | |
|
265 | [(x, self.headers[x]) for x in self.headers | |
|
266 | if x.lower().startswith('proxy-')]) | |
|
267 | self._set_hostport(self.host, self.port) | |
|
268 | self.send('CONNECT %s:%d HTTP/1.0\r\n' % (self.realhost, self.realport)) | |
|
269 | for header in proxyheaders.iteritems(): | |
|
270 | self.send('%s: %s\r\n' % header) | |
|
271 | self.send('\r\n') | |
|
272 | ||
|
273 | # majority of the following code is duplicated from | |
|
274 | # httplib.HTTPConnection as there are no adequate places to | |
|
275 | # override functions to provide the needed functionality | |
|
276 | res = self.response_class(self.sock, | |
|
277 | strict=self.strict, | |
|
278 | method=self._method) | |
|
279 | ||
|
280 | while True: | |
|
281 | version, status, reason = res._read_status() | |
|
282 | if status != httplib.CONTINUE: | |
|
283 | break | |
|
284 | while True: | |
|
285 | skip = res.fp.readline().strip() | |
|
286 | if not skip: | |
|
287 | break | |
|
288 | res.status = status | |
|
289 | res.reason = reason.strip() | |
|
290 | ||
|
291 | if res.status == 200: | |
|
292 | while True: | |
|
293 | line = res.fp.readline() | |
|
294 | if line == '\r\n': | |
|
295 | break | |
|
296 | return True | |
|
297 | ||
|
298 | if version == 'HTTP/1.0': | |
|
299 | res.version = 10 | |
|
300 | elif version.startswith('HTTP/1.'): | |
|
301 | res.version = 11 | |
|
302 | elif version == 'HTTP/0.9': | |
|
303 | res.version = 9 | |
|
304 | else: | |
|
305 | raise httplib.UnknownProtocol(version) | |
|
306 | ||
|
307 | if res.version == 9: | |
|
308 | res.length = None | |
|
309 | res.chunked = 0 | |
|
310 | res.will_close = 1 | |
|
311 | res.msg = httplib.HTTPMessage(cStringIO.StringIO()) | |
|
312 | return False | |
|
313 | ||
|
314 | res.msg = httplib.HTTPMessage(res.fp) | |
|
315 | res.msg.fp = None | |
|
316 | ||
|
317 | # are we using the chunked-style of transfer encoding? | |
|
318 | trenc = res.msg.getheader('transfer-encoding') | |
|
319 | if trenc and trenc.lower() == "chunked": | |
|
320 | res.chunked = 1 | |
|
321 | res.chunk_left = None | |
|
322 | else: | |
|
323 | res.chunked = 0 | |
|
324 | ||
|
325 | # will the connection close at the end of the response? | |
|
326 | res.will_close = res._check_close() | |
|
327 | ||
|
328 | # do we have a Content-Length? | |
|
329 | # NOTE: RFC 2616, S4.4, #3 says we ignore this if tr_enc is "chunked" | |
|
330 | length = res.msg.getheader('content-length') | |
|
331 | if length and not res.chunked: | |
|
332 | try: | |
|
333 | res.length = int(length) | |
|
334 | except ValueError: | |
|
335 | res.length = None | |
|
336 | else: | |
|
337 | if res.length < 0: # ignore nonsensical negative lengths | |
|
338 | res.length = None | |
|
339 | else: | |
|
340 | res.length = None | |
|
341 | ||
|
342 | # does the body have a fixed length? (of zero) | |
|
343 | if (status == httplib.NO_CONTENT or status == httplib.NOT_MODIFIED or | |
|
344 | 100 <= status < 200 or # 1xx codes | |
|
345 | res._method == 'HEAD'): | |
|
346 | res.length = 0 | |
|
347 | ||
|
348 | # if the connection remains open, and we aren't using chunked, and | |
|
349 | # a content-length was not provided, then assume that the connection | |
|
350 | # WILL close. | |
|
351 | if (not res.will_close and | |
|
352 | not res.chunked and | |
|
353 | res.length is None): | |
|
354 | res.will_close = 1 | |
|
355 | ||
|
356 | self.proxyres = res | |
|
357 | ||
|
358 | return False | |
|
359 | ||
|
360 | def connect(self): | |
|
361 | if has_https and self.realhost: # use CONNECT proxy | |
|
362 | self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
|
363 | self.sock.connect((self.host, self.port)) | |
|
364 | if self._proxytunnel(): | |
|
365 | # we do not support client x509 certificates | |
|
366 | self.sock = _ssl_wrap_socket(self.sock, None, None) | |
|
367 | else: | |
|
368 | keepalive.HTTPConnection.connect(self) | |
|
369 | ||
|
370 | def getresponse(self): | |
|
371 | proxyres = getattr(self, 'proxyres', None) | |
|
372 | if proxyres: | |
|
373 | if proxyres.will_close: | |
|
374 | self.close() | |
|
375 | self.proxyres = None | |
|
376 | return proxyres | |
|
377 | return keepalive.HTTPConnection.getresponse(self) | |
|
378 | ||
|
252 | 379 | class httphandler(keepalive.HTTPHandler): |
|
253 | 380 | def http_open(self, req): |
|
254 | 381 | return self.do_open(httpconnection, req) |
|
255 | 382 | |
|
383 | def _start_transaction(self, h, req): | |
|
384 | if req.get_selector() == req.get_full_url(): # has proxy | |
|
385 | urlparts = urlparse.urlparse(req.get_selector()) | |
|
386 | if urlparts[0] == 'https': # only use CONNECT for HTTPS | |
|
387 | if ':' in urlparts[1]: | |
|
388 | realhost, realport = urlparts[1].split(':') | |
|
389 | else: | |
|
390 | realhost = urlparts[1] | |
|
391 | realport = 443 | |
|
392 | ||
|
393 | h.realhost = realhost | |
|
394 | h.realport = realport | |
|
395 | h.headers = req.headers.copy() | |
|
396 | h.headers.update(self.parent.addheaders) | |
|
397 | return keepalive.HTTPHandler._start_transaction(self, h, req) | |
|
398 | ||
|
399 | h.realhost = None | |
|
400 | h.realport = None | |
|
401 | h.headers = None | |
|
402 | return keepalive.HTTPHandler._start_transaction(self, h, req) | |
|
403 | ||
|
256 | 404 | def __del__(self): |
|
257 | 405 | self.close_all() |
|
258 | 406 | |
|
259 | has_https = hasattr(urllib2, 'HTTPSHandler') | |
|
260 | 407 | if has_https: |
|
261 | 408 | class httpsconnection(httplib.HTTPSConnection): |
|
262 | 409 | response_class = keepalive.HTTPResponse |
General Comments 0
You need to be logged in to leave comments.
Login now