Show More
@@ -23,6 +23,9 b'' | |||||
23 | # - import md5 function from a local util module |
|
23 | # - import md5 function from a local util module | |
24 | # Modified by Martin Geisler: |
|
24 | # Modified by Martin Geisler: | |
25 | # - moved md5 function from local util module to this module |
|
25 | # - moved md5 function from local util module to this module | |
|
26 | # Modified by Augie Fackler: | |||
|
27 | # - add safesend method and use it to prevent broken pipe errors | |||
|
28 | # on large POST requests | |||
26 |
|
29 | |||
27 | """An HTTP handler for urllib2 that supports HTTP 1.1 and keepalive. |
|
30 | """An HTTP handler for urllib2 that supports HTTP 1.1 and keepalive. | |
28 |
|
31 | |||
@@ -108,10 +111,11 b' EXTRA ATTRIBUTES AND METHODS' | |||||
108 |
|
111 | |||
109 | # $Id: keepalive.py,v 1.14 2006/04/04 21:00:32 mstenner Exp $ |
|
112 | # $Id: keepalive.py,v 1.14 2006/04/04 21:00:32 mstenner Exp $ | |
110 |
|
113 | |||
111 |
import |
|
114 | import errno | |
112 | import httplib |
|
115 | import httplib | |
113 | import socket |
|
116 | import socket | |
114 | import thread |
|
117 | import thread | |
|
118 | import urllib2 | |||
115 |
|
119 | |||
116 | DEBUG = None |
|
120 | DEBUG = None | |
117 |
|
121 | |||
@@ -495,10 +499,76 b' class HTTPResponse(httplib.HTTPResponse)' | |||||
495 | break |
|
499 | break | |
496 | return list |
|
500 | return list | |
497 |
|
501 | |||
|
502 | def safesend(self, str): | |||
|
503 | """Send `str' to the server. | |||
|
504 | ||||
|
505 | Shamelessly ripped off from httplib to patch a bad behavior. | |||
|
506 | """ | |||
|
507 | # _broken_pipe_resp is an attribute we set in this function | |||
|
508 | # if the socket is closed while we're sending data but | |||
|
509 | # the server sent us a response before hanging up. | |||
|
510 | # In that case, we want to pretend to send the rest of the | |||
|
511 | # outgoing data, and then let the user use getresponse() | |||
|
512 | # (which we wrap) to get this last response before | |||
|
513 | # opening a new socket. | |||
|
514 | if getattr(self, '_broken_pipe_resp', None) is not None: | |||
|
515 | return | |||
|
516 | ||||
|
517 | if self.sock is None: | |||
|
518 | if self.auto_open: | |||
|
519 | self.connect() | |||
|
520 | else: | |||
|
521 | raise httplib.NotConnected() | |||
|
522 | ||||
|
523 | # send the data to the server. if we get a broken pipe, then close | |||
|
524 | # the socket. we want to reconnect when somebody tries to send again. | |||
|
525 | # | |||
|
526 | # NOTE: we DO propagate the error, though, because we cannot simply | |||
|
527 | # ignore the error... the caller will know if they can retry. | |||
|
528 | if self.debuglevel > 0: | |||
|
529 | print "send:", repr(str) | |||
|
530 | try: | |||
|
531 | blocksize=8192 | |||
|
532 | if hasattr(str,'read') : | |||
|
533 | if self.debuglevel > 0: print "sendIng a read()able" | |||
|
534 | data=str.read(blocksize) | |||
|
535 | while data: | |||
|
536 | self.sock.sendall(data) | |||
|
537 | data=str.read(blocksize) | |||
|
538 | else: | |||
|
539 | self.sock.sendall(str) | |||
|
540 | except socket.error, v: | |||
|
541 | reraise = True | |||
|
542 | if v[0] == errno.EPIPE: # Broken pipe | |||
|
543 | if self._HTTPConnection__state == httplib._CS_REQ_SENT: | |||
|
544 | self._broken_pipe_resp = None | |||
|
545 | self._broken_pipe_resp = self.getresponse() | |||
|
546 | reraise = False | |||
|
547 | self.close() | |||
|
548 | if reraise: | |||
|
549 | raise | |||
|
550 | ||||
|
551 | def wrapgetresponse(cls): | |||
|
552 | """Wraps getresponse in cls with a broken-pipe sane version. | |||
|
553 | """ | |||
|
554 | def safegetresponse(self): | |||
|
555 | # In safesend() we might set the _broken_pipe_resp | |||
|
556 | # attribute, in which case the socket has already | |||
|
557 | # been closed and we just need to give them the response | |||
|
558 | # back. Otherwise, we use the normal response path. | |||
|
559 | r = getattr(self, '_broken_pipe_resp', None) | |||
|
560 | if r is not None: | |||
|
561 | return r | |||
|
562 | return cls.getresponse(self) | |||
|
563 | safegetresponse.__doc__ = cls.getresponse.__doc__ | |||
|
564 | return safegetresponse | |||
498 |
|
565 | |||
499 | class HTTPConnection(httplib.HTTPConnection): |
|
566 | class HTTPConnection(httplib.HTTPConnection): | |
500 | # use the modified response class |
|
567 | # use the modified response class | |
501 | response_class = HTTPResponse |
|
568 | response_class = HTTPResponse | |
|
569 | send = safesend | |||
|
570 | getresponse = wrapgetresponse(httplib.HTTPConnection) | |||
|
571 | ||||
502 |
|
572 | |||
503 | ######################################################################### |
|
573 | ######################################################################### | |
504 | ##### TEST FUNCTIONS |
|
574 | ##### TEST FUNCTIONS |
@@ -408,10 +408,14 b' class httphandler(keepalive.HTTPHandler)' | |||||
408 | self.close_all() |
|
408 | self.close_all() | |
409 |
|
409 | |||
410 | if has_https: |
|
410 | if has_https: | |
411 |
class |
|
411 | class BetterHTTPS(httplib.HTTPSConnection): | |
|
412 | send = keepalive.safesend | |||
|
413 | ||||
|
414 | class httpsconnection(BetterHTTPS): | |||
412 | response_class = keepalive.HTTPResponse |
|
415 | response_class = keepalive.HTTPResponse | |
413 | # must be able to send big bundle as stream. |
|
416 | # must be able to send big bundle as stream. | |
414 |
send = _gen_sendfile( |
|
417 | send = _gen_sendfile(BetterHTTPS) | |
|
418 | getresponse = keepalive.wrapgetresponse(httplib.HTTPSConnection) | |||
415 |
|
419 | |||
416 | class httpshandler(keepalive.KeepAliveHandler, urllib2.HTTPSHandler): |
|
420 | class httpshandler(keepalive.KeepAliveHandler, urllib2.HTTPSHandler): | |
417 | def __init__(self, ui): |
|
421 | def __init__(self, ui): |
General Comments 0
You need to be logged in to leave comments.
Login now