##// END OF EJS Templates
keepalive: handle broken pipes gracefully during large POSTs
Augie Fackler -
r9726:430e59ff default
parent child Browse files
Show More
@@ -23,6 +23,9 b''
23 23 # - import md5 function from a local util module
24 24 # Modified by Martin Geisler:
25 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 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 112 # $Id: keepalive.py,v 1.14 2006/04/04 21:00:32 mstenner Exp $
110 113
111 import urllib2
114 import errno
112 115 import httplib
113 116 import socket
114 117 import thread
118 import urllib2
115 119
116 120 DEBUG = None
117 121
@@ -495,10 +499,76 b' class HTTPResponse(httplib.HTTPResponse)'
495 499 break
496 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 566 class HTTPConnection(httplib.HTTPConnection):
500 567 # use the modified response class
501 568 response_class = HTTPResponse
569 send = safesend
570 getresponse = wrapgetresponse(httplib.HTTPConnection)
571
502 572
503 573 #########################################################################
504 574 ##### TEST FUNCTIONS
@@ -408,10 +408,14 b' class httphandler(keepalive.HTTPHandler)'
408 408 self.close_all()
409 409
410 410 if has_https:
411 class httpsconnection(httplib.HTTPSConnection):
411 class BetterHTTPS(httplib.HTTPSConnection):
412 send = keepalive.safesend
413
414 class httpsconnection(BetterHTTPS):
412 415 response_class = keepalive.HTTPResponse
413 416 # must be able to send big bundle as stream.
414 send = _gen_sendfile(httplib.HTTPSConnection)
417 send = _gen_sendfile(BetterHTTPS)
418 getresponse = keepalive.wrapgetresponse(httplib.HTTPSConnection)
415 419
416 420 class httpshandler(keepalive.KeepAliveHandler, urllib2.HTTPSHandler):
417 421 def __init__(self, ui):
General Comments 0
You need to be logged in to leave comments. Login now