Show More
@@ -262,108 +262,11 b' class httpconnection(keepalive.HTTPConne' | |||||
262 | # must be able to send big bundle as stream. |
|
262 | # must be able to send big bundle as stream. | |
263 | send = _gen_sendfile(keepalive.HTTPConnection) |
|
263 | send = _gen_sendfile(keepalive.HTTPConnection) | |
264 |
|
264 | |||
265 | def _proxytunnel(self): |
|
|||
266 | proxyheaders = dict( |
|
|||
267 | [(x, self.headers[x]) for x in self.headers |
|
|||
268 | if x.lower().startswith('proxy-')]) |
|
|||
269 | self._set_hostport(self.host, self.port) |
|
|||
270 | self.send('CONNECT %s:%d HTTP/1.0\r\n' % (self.realhost, self.realport)) |
|
|||
271 | for header in proxyheaders.iteritems(): |
|
|||
272 | self.send('%s: %s\r\n' % header) |
|
|||
273 | self.send('\r\n') |
|
|||
274 |
|
||||
275 | # majority of the following code is duplicated from |
|
|||
276 | # httplib.HTTPConnection as there are no adequate places to |
|
|||
277 | # override functions to provide the needed functionality |
|
|||
278 | res = self.response_class(self.sock, |
|
|||
279 | strict=self.strict, |
|
|||
280 | method=self._method) |
|
|||
281 |
|
||||
282 | while True: |
|
|||
283 | version, status, reason = res._read_status() |
|
|||
284 | if status != httplib.CONTINUE: |
|
|||
285 | break |
|
|||
286 | while True: |
|
|||
287 | skip = res.fp.readline().strip() |
|
|||
288 | if not skip: |
|
|||
289 | break |
|
|||
290 | res.status = status |
|
|||
291 | res.reason = reason.strip() |
|
|||
292 |
|
||||
293 | if res.status == 200: |
|
|||
294 | while True: |
|
|||
295 | line = res.fp.readline() |
|
|||
296 | if line == '\r\n': |
|
|||
297 | break |
|
|||
298 | return True |
|
|||
299 |
|
||||
300 | if version == 'HTTP/1.0': |
|
|||
301 | res.version = 10 |
|
|||
302 | elif version.startswith('HTTP/1.'): |
|
|||
303 | res.version = 11 |
|
|||
304 | elif version == 'HTTP/0.9': |
|
|||
305 | res.version = 9 |
|
|||
306 | else: |
|
|||
307 | raise httplib.UnknownProtocol(version) |
|
|||
308 |
|
||||
309 | if res.version == 9: |
|
|||
310 | res.length = None |
|
|||
311 | res.chunked = 0 |
|
|||
312 | res.will_close = 1 |
|
|||
313 | res.msg = httplib.HTTPMessage(cStringIO.StringIO()) |
|
|||
314 | return False |
|
|||
315 |
|
||||
316 | res.msg = httplib.HTTPMessage(res.fp) |
|
|||
317 | res.msg.fp = None |
|
|||
318 |
|
||||
319 | # are we using the chunked-style of transfer encoding? |
|
|||
320 | trenc = res.msg.getheader('transfer-encoding') |
|
|||
321 | if trenc and trenc.lower() == "chunked": |
|
|||
322 | res.chunked = 1 |
|
|||
323 | res.chunk_left = None |
|
|||
324 | else: |
|
|||
325 | res.chunked = 0 |
|
|||
326 |
|
||||
327 | # will the connection close at the end of the response? |
|
|||
328 | res.will_close = res._check_close() |
|
|||
329 |
|
||||
330 | # do we have a Content-Length? |
|
|||
331 | # NOTE: RFC 2616, S4.4, #3 says we ignore this if tr_enc is "chunked" |
|
|||
332 | length = res.msg.getheader('content-length') |
|
|||
333 | if length and not res.chunked: |
|
|||
334 | try: |
|
|||
335 | res.length = int(length) |
|
|||
336 | except ValueError: |
|
|||
337 | res.length = None |
|
|||
338 | else: |
|
|||
339 | if res.length < 0: # ignore nonsensical negative lengths |
|
|||
340 | res.length = None |
|
|||
341 | else: |
|
|||
342 | res.length = None |
|
|||
343 |
|
||||
344 | # does the body have a fixed length? (of zero) |
|
|||
345 | if (status == httplib.NO_CONTENT or status == httplib.NOT_MODIFIED or |
|
|||
346 | 100 <= status < 200 or # 1xx codes |
|
|||
347 | res._method == 'HEAD'): |
|
|||
348 | res.length = 0 |
|
|||
349 |
|
||||
350 | # if the connection remains open, and we aren't using chunked, and |
|
|||
351 | # a content-length was not provided, then assume that the connection |
|
|||
352 | # WILL close. |
|
|||
353 | if (not res.will_close and |
|
|||
354 | not res.chunked and |
|
|||
355 | res.length is None): |
|
|||
356 | res.will_close = 1 |
|
|||
357 |
|
||||
358 | self.proxyres = res |
|
|||
359 |
|
||||
360 | return False |
|
|||
361 |
|
||||
362 | def connect(self): |
|
265 | def connect(self): | |
363 | if has_https and self.realhost: # use CONNECT proxy |
|
266 | if has_https and self.realhost: # use CONNECT proxy | |
364 | self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
|
267 | self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
365 | self.sock.connect((self.host, self.port)) |
|
268 | self.sock.connect((self.host, self.port)) | |
366 |
if self |
|
269 | if _generic_proxytunnel(self): | |
367 | # we do not support client x509 certificates |
|
270 | # we do not support client x509 certificates | |
368 | self.sock = _ssl_wrap_socket(self.sock, None, None) |
|
271 | self.sock = _ssl_wrap_socket(self.sock, None, None) | |
369 | else: |
|
272 | else: | |
@@ -378,30 +281,141 b' class httpconnection(keepalive.HTTPConne' | |||||
378 | return proxyres |
|
281 | return proxyres | |
379 | return keepalive.HTTPConnection.getresponse(self) |
|
282 | return keepalive.HTTPConnection.getresponse(self) | |
380 |
|
283 | |||
|
284 | # general transaction handler to support different ways to handle | |||
|
285 | # HTTPS proxying before and after Python 2.6.3. | |||
|
286 | def _generic_start_transaction(handler, h, req): | |||
|
287 | if hasattr(req, '_tunnel_host') and req._tunnel_host: | |||
|
288 | tunnel_host = req._tunnel_host | |||
|
289 | if tunnel_host[:7] not in ['http://', 'https:/']: | |||
|
290 | tunnel_host = 'https://' + tunnel_host | |||
|
291 | new_tunnel = True | |||
|
292 | else: | |||
|
293 | tunnel_host = req.get_selector() | |||
|
294 | new_tunnel = False | |||
|
295 | ||||
|
296 | if new_tunnel or tunnel_host == req.get_full_url(): # has proxy | |||
|
297 | urlparts = urlparse.urlparse(tunnel_host) | |||
|
298 | if new_tunnel or urlparts[0] == 'https': # only use CONNECT for HTTPS | |||
|
299 | if ':' in urlparts[1]: | |||
|
300 | realhost, realport = urlparts[1].split(':') | |||
|
301 | realport = int(realport) | |||
|
302 | else: | |||
|
303 | realhost = urlparts[1] | |||
|
304 | realport = 443 | |||
|
305 | ||||
|
306 | h.realhost = realhost | |||
|
307 | h.realport = realport | |||
|
308 | h.headers = req.headers.copy() | |||
|
309 | h.headers.update(handler.parent.addheaders) | |||
|
310 | return | |||
|
311 | ||||
|
312 | h.realhost = None | |||
|
313 | h.realport = None | |||
|
314 | h.headers = None | |||
|
315 | ||||
|
316 | def _generic_proxytunnel(self): | |||
|
317 | proxyheaders = dict( | |||
|
318 | [(x, self.headers[x]) for x in self.headers | |||
|
319 | if x.lower().startswith('proxy-')]) | |||
|
320 | self._set_hostport(self.host, self.port) | |||
|
321 | self.send('CONNECT %s:%d HTTP/1.0\r\n' % (self.realhost, self.realport)) | |||
|
322 | for header in proxyheaders.iteritems(): | |||
|
323 | self.send('%s: %s\r\n' % header) | |||
|
324 | self.send('\r\n') | |||
|
325 | ||||
|
326 | # majority of the following code is duplicated from | |||
|
327 | # httplib.HTTPConnection as there are no adequate places to | |||
|
328 | # override functions to provide the needed functionality | |||
|
329 | res = self.response_class(self.sock, | |||
|
330 | strict=self.strict, | |||
|
331 | method=self._method) | |||
|
332 | ||||
|
333 | while True: | |||
|
334 | version, status, reason = res._read_status() | |||
|
335 | if status != httplib.CONTINUE: | |||
|
336 | break | |||
|
337 | while True: | |||
|
338 | skip = res.fp.readline().strip() | |||
|
339 | if not skip: | |||
|
340 | break | |||
|
341 | res.status = status | |||
|
342 | res.reason = reason.strip() | |||
|
343 | ||||
|
344 | if res.status == 200: | |||
|
345 | while True: | |||
|
346 | line = res.fp.readline() | |||
|
347 | if line == '\r\n': | |||
|
348 | break | |||
|
349 | return True | |||
|
350 | ||||
|
351 | if version == 'HTTP/1.0': | |||
|
352 | res.version = 10 | |||
|
353 | elif version.startswith('HTTP/1.'): | |||
|
354 | res.version = 11 | |||
|
355 | elif version == 'HTTP/0.9': | |||
|
356 | res.version = 9 | |||
|
357 | else: | |||
|
358 | raise httplib.UnknownProtocol(version) | |||
|
359 | ||||
|
360 | if res.version == 9: | |||
|
361 | res.length = None | |||
|
362 | res.chunked = 0 | |||
|
363 | res.will_close = 1 | |||
|
364 | res.msg = httplib.HTTPMessage(cStringIO.StringIO()) | |||
|
365 | return False | |||
|
366 | ||||
|
367 | res.msg = httplib.HTTPMessage(res.fp) | |||
|
368 | res.msg.fp = None | |||
|
369 | ||||
|
370 | # are we using the chunked-style of transfer encoding? | |||
|
371 | trenc = res.msg.getheader('transfer-encoding') | |||
|
372 | if trenc and trenc.lower() == "chunked": | |||
|
373 | res.chunked = 1 | |||
|
374 | res.chunk_left = None | |||
|
375 | else: | |||
|
376 | res.chunked = 0 | |||
|
377 | ||||
|
378 | # will the connection close at the end of the response? | |||
|
379 | res.will_close = res._check_close() | |||
|
380 | ||||
|
381 | # do we have a Content-Length? | |||
|
382 | # NOTE: RFC 2616, S4.4, #3 says we ignore this if tr_enc is "chunked" | |||
|
383 | length = res.msg.getheader('content-length') | |||
|
384 | if length and not res.chunked: | |||
|
385 | try: | |||
|
386 | res.length = int(length) | |||
|
387 | except ValueError: | |||
|
388 | res.length = None | |||
|
389 | else: | |||
|
390 | if res.length < 0: # ignore nonsensical negative lengths | |||
|
391 | res.length = None | |||
|
392 | else: | |||
|
393 | res.length = None | |||
|
394 | ||||
|
395 | # does the body have a fixed length? (of zero) | |||
|
396 | if (status == httplib.NO_CONTENT or status == httplib.NOT_MODIFIED or | |||
|
397 | 100 <= status < 200 or # 1xx codes | |||
|
398 | res._method == 'HEAD'): | |||
|
399 | res.length = 0 | |||
|
400 | ||||
|
401 | # if the connection remains open, and we aren't using chunked, and | |||
|
402 | # a content-length was not provided, then assume that the connection | |||
|
403 | # WILL close. | |||
|
404 | if (not res.will_close and | |||
|
405 | not res.chunked and | |||
|
406 | res.length is None): | |||
|
407 | res.will_close = 1 | |||
|
408 | ||||
|
409 | self.proxyres = res | |||
|
410 | ||||
|
411 | return False | |||
|
412 | ||||
381 | class httphandler(keepalive.HTTPHandler): |
|
413 | class httphandler(keepalive.HTTPHandler): | |
382 | def http_open(self, req): |
|
414 | def http_open(self, req): | |
383 | return self.do_open(httpconnection, req) |
|
415 | return self.do_open(httpconnection, req) | |
384 |
|
416 | |||
385 | def _start_transaction(self, h, req): |
|
417 | def _start_transaction(self, h, req): | |
386 | if req.get_selector() == req.get_full_url(): # has proxy |
|
418 | _generic_start_transaction(self, h, req) | |
387 | urlparts = urlparse.urlparse(req.get_selector()) |
|
|||
388 | if urlparts[0] == 'https': # only use CONNECT for HTTPS |
|
|||
389 | if ':' in urlparts[1]: |
|
|||
390 | realhost, realport = urlparts[1].split(':') |
|
|||
391 | realport = int(realport) |
|
|||
392 | else: |
|
|||
393 | realhost = urlparts[1] |
|
|||
394 | realport = 443 |
|
|||
395 |
|
||||
396 | h.realhost = realhost |
|
|||
397 | h.realport = realport |
|
|||
398 | h.headers = req.headers.copy() |
|
|||
399 | h.headers.update(self.parent.addheaders) |
|
|||
400 | return keepalive.HTTPHandler._start_transaction(self, h, req) |
|
|||
401 |
|
||||
402 | h.realhost = None |
|
|||
403 | h.realport = None |
|
|||
404 | h.headers = None |
|
|||
405 | return keepalive.HTTPHandler._start_transaction(self, h, req) |
|
419 | return keepalive.HTTPHandler._start_transaction(self, h, req) | |
406 |
|
420 | |||
407 | def __del__(self): |
|
421 | def __del__(self): | |
@@ -417,6 +431,15 b' if has_https:' | |||||
417 | send = _gen_sendfile(BetterHTTPS) |
|
431 | send = _gen_sendfile(BetterHTTPS) | |
418 | getresponse = keepalive.wrapgetresponse(httplib.HTTPSConnection) |
|
432 | getresponse = keepalive.wrapgetresponse(httplib.HTTPSConnection) | |
419 |
|
433 | |||
|
434 | def connect(self): | |||
|
435 | if self.realhost: # use CONNECT proxy | |||
|
436 | self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |||
|
437 | self.sock.connect((self.host, self.port)) | |||
|
438 | if _generic_proxytunnel(self): | |||
|
439 | self.sock = _ssl_wrap_socket(self.sock, self.cert_file, self.key_file) | |||
|
440 | else: | |||
|
441 | BetterHTTPS.connect(self) | |||
|
442 | ||||
420 | class httpshandler(keepalive.KeepAliveHandler, urllib2.HTTPSHandler): |
|
443 | class httpshandler(keepalive.KeepAliveHandler, urllib2.HTTPSHandler): | |
421 | def __init__(self, ui): |
|
444 | def __init__(self, ui): | |
422 | keepalive.KeepAliveHandler.__init__(self) |
|
445 | keepalive.KeepAliveHandler.__init__(self) | |
@@ -424,6 +447,10 b' if has_https:' | |||||
424 | self.ui = ui |
|
447 | self.ui = ui | |
425 | self.pwmgr = passwordmgr(self.ui) |
|
448 | self.pwmgr = passwordmgr(self.ui) | |
426 |
|
449 | |||
|
450 | def _start_transaction(self, h, req): | |||
|
451 | _generic_start_transaction(self, h, req) | |||
|
452 | return keepalive.KeepAliveHandler._start_transaction(self, h, req) | |||
|
453 | ||||
427 | def https_open(self, req): |
|
454 | def https_open(self, req): | |
428 | self.auth = self.pwmgr.readauthtoken(req.get_full_url()) |
|
455 | self.auth = self.pwmgr.readauthtoken(req.get_full_url()) | |
429 | return self.do_open(self._makeconnection, req) |
|
456 | return self.do_open(self._makeconnection, req) |
General Comments 0
You need to be logged in to leave comments.
Login now