diff -r c85f19c66e8d -r bf855efe5664 mercurial/httppeer.py --- a/mercurial/httppeer.py Thu Apr 13 22:19:28 2017 -0700 +++ b/mercurial/httppeer.py Fri Apr 14 00:33:56 2017 -0700 @@ -75,6 +75,41 @@ return result +def _wraphttpresponse(resp): + """Wrap an HTTPResponse with common error handlers. + + This ensures that any I/O from any consumer raises the appropriate + error and messaging. + """ + origread = resp.read + + class readerproxy(resp.__class__): + def read(self, size=None): + try: + return origread(size) + except httplib.IncompleteRead as e: + # e.expected is an integer if length known or None otherwise. + if e.expected: + msg = _('HTTP request error (incomplete response; ' + 'expected %d bytes got %d)') % (e.expected, + len(e.partial)) + else: + msg = _('HTTP request error (incomplete response)') + + raise error.RichIOError( + msg, + hint=_('this may be an intermittent network failure; ' + 'if the error persists, consider contacting the ' + 'network or server operator')) + except httplib.HTTPException as e: + raise error.RichIOError( + _('HTTP request error (%s)') % e, + hint=_('this may be an intermittent failure; ' + 'if the error persists, consider contacting the ' + 'network or server operator')) + + resp.__class__ = readerproxy + class httppeer(wireproto.wirepeer): def __init__(self, ui, path): self.path = path @@ -223,6 +258,10 @@ self.ui.debug('http error while sending %s command\n' % cmd) self.ui.traceback() raise IOError(None, inst) + + # Insert error handlers for common I/O failures. + _wraphttpresponse(resp) + # record the url we got redirected to resp_url = resp.geturl() if resp_url.endswith(qs):