# HG changeset patch # User Cédric Krier # Date 2018-10-04 09:28:48 # Node ID 6509fcec830cc3c0c087cfa274f76d85507808b8 # Parent 208303a8172c28d5577631bb2637897a700707bf url: allow to configure timeout on http connection By default, httplib.HTTPConnection opens connection with no timeout. If the server is hanging, Mercurial will wait indefinitely. This may be an issue for automated scripts. Differential Revision: https://phab.mercurial-scm.org/D4878 diff --git a/mercurial/configitems.py b/mercurial/configitems.py --- a/mercurial/configitems.py +++ b/mercurial/configitems.py @@ -737,6 +737,11 @@ coreconfigitem('http_proxy', 'passwd', coreconfigitem('http_proxy', 'user', default=None, ) + +coreconfigitem('http', 'timeout', + default=None, +) + coreconfigitem('logtoprocess', 'commandexception', default=None, ) diff --git a/mercurial/help/config.txt b/mercurial/help/config.txt --- a/mercurial/help/config.txt +++ b/mercurial/help/config.txt @@ -1322,6 +1322,15 @@ proxy. Optional. Always use the proxy, even for localhost and any entries in ``http_proxy.no``. (default: False) +``http`` +---------- + +Used to configure access to Mercurial repositories via HTTP. + +``timeout`` + If set, blocking operations will timeout after that many seconds. + (default: None) + ``merge`` --------- diff --git a/mercurial/keepalive.py b/mercurial/keepalive.py --- a/mercurial/keepalive.py +++ b/mercurial/keepalive.py @@ -172,8 +172,9 @@ class ConnectionManager(object): return dict(self._hostmap) class KeepAliveHandler(object): - def __init__(self): + def __init__(self, timeout=None): self._cm = ConnectionManager() + self._timeout = timeout self.requestscount = 0 self.sentbytescount = 0 @@ -234,7 +235,7 @@ class KeepAliveHandler(object): h = self._cm.get_ready_conn(host) else: # no (working) free connections were found. Create a new one. - h = http_class(host) + h = http_class(host, timeout=self._timeout) if DEBUG: DEBUG.info("creating new connection to %s (%d)", host, id(h)) diff --git a/mercurial/url.py b/mercurial/url.py --- a/mercurial/url.py +++ b/mercurial/url.py @@ -317,8 +317,8 @@ class logginghttpconnection(keepalive.HT class logginghttphandler(httphandler): """HTTP handler that logs socket I/O.""" - def __init__(self, logfh, name, observeropts): - super(logginghttphandler, self).__init__() + def __init__(self, logfh, name, observeropts, timeout=None): + super(logginghttphandler, self).__init__(timeout=timeout) self._logfh = logfh self._logname = name @@ -365,8 +365,8 @@ if has_https: sslutil.validatesocket(self.sock) class httpshandler(keepalive.KeepAliveHandler, urlreq.httpshandler): - def __init__(self, ui): - keepalive.KeepAliveHandler.__init__(self) + def __init__(self, ui, timeout=None): + keepalive.KeepAliveHandler.__init__(self, timeout=timeout) urlreq.httpshandler.__init__(self) self.ui = ui self.pwmgr = passwordmgr(self.ui, @@ -525,18 +525,19 @@ def opener(ui, authinfo=None, useragent= ``sendaccept`` allows controlling whether the ``Accept`` request header is sent. The header is sent by default. ''' + timeout = ui.configwith(float, 'http', 'timeout') handlers = [] if loggingfh: handlers.append(logginghttphandler(loggingfh, loggingname, - loggingopts or {})) + loggingopts or {}, timeout=timeout)) # We don't yet support HTTPS when logging I/O. If we attempt to open # an HTTPS URL, we'll likely fail due to unknown protocol. else: - handlers.append(httphandler()) + handlers.append(httphandler(timeout=timeout)) if has_https: - handlers.append(httpshandler(ui)) + handlers.append(httpshandler(ui, timeout=timeout)) handlers.append(proxyhandler(ui))