##// END OF EJS Templates
hgweb: pre-init mimetypes module (fixes ugly bug in python-2.6.2 mimetypes)...
hgweb: pre-init mimetypes module (fixes ugly bug in python-2.6.2 mimetypes) The ugly initialization hack in mimetypes' initialization procedure can make hg serve hit the maximum recursion depth when in threaded mode.

File last commit:

r8206:cce63ef1 default
r8224:1075f5c1 default
Show More
httprepo.py
244 lines | 8.7 KiB | text/x-python | PythonLexer
mpm@selenic.com
Break apart hg.py...
r1089 # httprepo.py - HTTP repository proxy classes for mercurial
#
Vadim Gelfer
update copyrights.
r2859 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
# Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
mpm@selenic.com
Break apart hg.py...
r1089 #
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
Matt Mackall
Autodetect static-http
r7211 from node import bin, hex, nullid
Matt Mackall
Simplify i18n imports
r3891 from i18n import _
Matt Mackall
fix-up references to repo.RepoError
r5176 import repo, os, urllib, urllib2, urlparse, zlib, util, httplib
Matt Mackall
error: move repo errors...
r7637 import errno, socket, changegroup, statichttprepo, error, url
Alexis S. L. Carvalho
Work around urllib2 digest auth bug with Python < 2.5...
r4678
Matt Mackall
remove duplicate zgenerator in httprepo
r3661 def zgenerator(f):
zd = zlib.decompressobj()
try:
for chunk in util.filechunkiter(f):
yield zd.decompress(chunk)
Benoit Boissinot
remove unused variables
r7280 except httplib.HTTPException:
Matt Mackall
remove duplicate zgenerator in httprepo
r3661 raise IOError(None, _('connection ended unexpectedly'))
yield zd.flush()
Matt Mackall
remoterepo: no longer needed...
r6313 class httprepository(repo.repository):
mpm@selenic.com
Break apart hg.py...
r1089 def __init__(self, ui, path):
Vadim Gelfer
hooks: add url to changegroup, incoming, prechangegroup, pretxnchangegroup hooks...
r2673 self.path = path
Vadim Gelfer
http: query server for capabilities
r2442 self.caps = None
Andrei Vermel
Close keepalive connections to fix server traceback
r4132 self.handler = None
Vadim Gelfer
http: fix many problems with url parsing and auth. added proxy test....
r2337 scheme, netloc, urlpath, query, frag = urlparse.urlsplit(path)
if query or frag:
raise util.Abort(_('unsupported URL component: "%s"') %
(query or frag))
# urllib cannot handle URLs with embedded user or passwd
Benoit Boissinot
factor out the url handling from httprepo...
r7270 self._url, authinfo = url.getauthinfo(path)
mpm@selenic.com
Break apart hg.py...
r1089 self.ui = ui
Alexis S. L. Carvalho
httprepo: quote the path part of the URL...
r5066 self.ui.debug(_('using %s\n') % self._url)
Vadim Gelfer
http: fix many problems with url parsing and auth. added proxy test....
r2337
Benoit Boissinot
factor out the url handling from httprepo...
r7270 self.urlopener = url.opener(ui, authinfo)
Thomas Arendsen Hein
Removed trailing whitespace and tabs from python files
r4516
Steve Borho
close sockets on httprepository deletion (issue1487)...
r7752 def __del__(self):
for h in self.urlopener.handlers:
h.close()
if hasattr(h, "close_all"):
h.close_all()
Vadim Gelfer
hooks: add url to changegroup, incoming, prechangegroup, pretxnchangegroup hooks...
r2673 def url(self):
return self.path
Vadim Gelfer
http: query server for capabilities
r2442 # look up capabilities only when needed
def get_caps(self):
if self.caps is None:
try:
Martin Geisler
util: use built-in set and frozenset...
r8150 self.caps = set(self.do_read('capabilities').split())
Matt Mackall
error: move repo errors...
r7637 except error.RepoError:
Martin Geisler
util: use built-in set and frozenset...
r8150 self.caps = set()
Vadim Gelfer
push over http: client support....
r2465 self.ui.debug(_('capabilities: %s\n') %
(' '.join(self.caps or ['none'])))
Vadim Gelfer
http: query server for capabilities
r2442 return self.caps
capabilities = property(get_caps)
Vadim Gelfer
make push over http print good error message.
r1870 def lock(self):
raise util.Abort(_('operation not supported over http'))
mpm@selenic.com
Break apart hg.py...
r1089 def do_cmd(self, cmd, **args):
Vadim Gelfer
push over http: client support....
r2465 data = args.pop('data', None)
headers = args.pop('headers', {})
Benoit Boissinot
i18n part2: use '_' for all strings who are part of the user interface
r1402 self.ui.debug(_("sending %s command\n") % cmd)
mpm@selenic.com
Break apart hg.py...
r1089 q = {"cmd": cmd}
q.update(args)
Benoit Boissinot
httprepo: record the url after a request, makes pull + redirect works...
r3562 qs = '?%s' % urllib.urlencode(q)
cu = "%s%s" % (self._url, qs)
Thomas Arendsen Hein
Catch urllib's HTTPException and give a meaningful error message to the user....
r2294 try:
Thomas Arendsen Hein
Turn bundle file into a string for http push, for urllib2 over proxies.
r3567 if data:
Alexis S. L. Carvalho
Push over HTTP: really tell the user the size of the bundle
r5333 self.ui.debug(_("sending %s bytes\n") % len(data))
Benoit Boissinot
factor out the url handling from httprepo...
r7270 resp = self.urlopener.open(urllib2.Request(cu, data, headers))
Vadim Gelfer
http client: better work with authorization errors, broken sockets.
r2467 except urllib2.HTTPError, inst:
if inst.code == 401:
raise util.Abort(_('authorization failed'))
raise
Thomas Arendsen Hein
Catch urllib's HTTPException and give a meaningful error message to the user....
r2294 except httplib.HTTPException, inst:
Vadim Gelfer
http: print better error if exception happens.
r2336 self.ui.debug(_('http error while sending %s command\n') % cmd)
Matt Mackall
ui: print_exc() -> traceback()
r8206 self.ui.traceback()
Vadim Gelfer
http: print better error if exception happens.
r2336 raise IOError(None, inst)
Thomas Arendsen Hein
Catch python2.3's IndexError with bogus http proxy settings. (issue203)
r3399 except IndexError:
# this only happens with Python 2.3, later versions raise URLError
raise util.Abort(_('http error, possibly caused by proxy setting'))
Benoit Boissinot
httprepo: record the url after a request, makes pull + redirect works...
r3562 # record the url we got redirected to
Thomas Arendsen Hein
Inform the user about the new URL when being redirected via http....
r3570 resp_url = resp.geturl()
if resp_url.endswith(qs):
resp_url = resp_url[:-len(qs)]
if self._url != resp_url:
self.ui.status(_('real URL is %s\n') % resp_url)
self._url = resp_url
Vadim Gelfer
http client: support persistent connections....
r2435 try:
proto = resp.getheader('content-type')
except AttributeError:
proto = resp.headers['content-type']
mpm@selenic.com
Break apart hg.py...
r1089
Steve Borho
hide passwords in httprepo error messages
r8053 safeurl = url.hidepassword(self._url)
mpm@selenic.com
Break apart hg.py...
r1089 # accept old "text/plain" and "application/hg-changegroup" for now
Thomas Arendsen Hein
Cleanup of whitespace, indentation and line continuation.
r4633 if not (proto.startswith('application/mercurial-') or
proto.startswith('text/plain') or
proto.startswith('application/hg-changegroup')):
Patrick Mezard
Merge with crew-stable
r8055 self.ui.debug(_("requested URL: '%s'\n") % url.hidepassword(cu))
Matt Mackall
error: move repo errors...
r7637 raise error.RepoError(_("'%s' does not appear to be an hg repository")
Steve Borho
hide passwords in httprepo error messages
r8053 % safeurl)
mpm@selenic.com
Break apart hg.py...
r1089
Benoit Boissinot
fix handling of multiple Content-type headers...
r4012 if proto.startswith('application/mercurial-'):
try:
Thomas Arendsen Hein
Avoid float rounding errors when checking http protocol version.
r4356 version = proto.split('-', 1)[1]
version_info = tuple([int(n) for n in version.split('.')])
Benoit Boissinot
fix handling of multiple Content-type headers...
r4012 except ValueError:
Matt Mackall
error: move repo errors...
r7637 raise error.RepoError(_("'%s' sent a broken Content-Type "
Steve Borho
hide passwords in httprepo error messages
r8053 "header (%s)") % (safeurl, proto))
Thomas Arendsen Hein
Avoid float rounding errors when checking http protocol version.
r4356 if version_info > (0, 1):
Matt Mackall
error: move repo errors...
r7637 raise error.RepoError(_("'%s' uses newer protocol %s") %
Steve Borho
hide passwords in httprepo error messages
r8053 (safeurl, version))
mpm@selenic.com
Break apart hg.py...
r1089
return resp
Vadim Gelfer
http client: support persistent connections....
r2435 def do_read(self, cmd, **args):
fp = self.do_cmd(cmd, **args)
try:
return fp.read()
finally:
# if using keepalive, allow connection to be reused
fp.close()
Eric Hopper
Adding changegroupsubset and lookup to web protocol so pull -r and...
r3444 def lookup(self, key):
Bryan O'Sullivan
Push capability checking into protocol-level code.
r5259 self.requirecap('lookup', _('look up remote revision'))
Matt Mackall
httprepo: add support for passing lookup exception data
r3445 d = self.do_cmd("lookup", key = key).read()
success, data = d[:-1].split(' ', 1)
if int(success):
return bin(data)
Matt Mackall
error: move repo errors...
r7637 raise error.RepoError(data)
Eric Hopper
Adding changegroupsubset and lookup to web protocol so pull -r and...
r3444
mpm@selenic.com
Break apart hg.py...
r1089 def heads(self):
Vadim Gelfer
http client: support persistent connections....
r2435 d = self.do_read("heads")
mpm@selenic.com
Break apart hg.py...
r1089 try:
return map(bin, d[:-1].split(" "))
except:
Matt Mackall
error: move UnexpectedOutput (now ResponseError)
r7641 raise error.ResponseError(_("unexpected response:"), d)
mpm@selenic.com
Break apart hg.py...
r1089
def branches(self, nodes):
n = " ".join(map(hex, nodes))
Vadim Gelfer
http client: support persistent connections....
r2435 d = self.do_read("branches", nodes=n)
mpm@selenic.com
Break apart hg.py...
r1089 try:
br = [ tuple(map(bin, b.split(" "))) for b in d.splitlines() ]
return br
except:
Matt Mackall
error: move UnexpectedOutput (now ResponseError)
r7641 raise error.ResponseError(_("unexpected response:"), d)
mpm@selenic.com
Break apart hg.py...
r1089
def between(self, pairs):
Matt Mackall
protocol: avoid sending outrageously large between requests
r7342 batch = 8 # avoid giant requests
r = []
for i in xrange(0, len(pairs), batch):
n = " ".join(["-".join(map(hex, p)) for p in pairs[i:i + batch]])
d = self.do_read("between", pairs=n)
try:
r += [ l and map(bin, l.split(" ")) or [] for l in d.splitlines() ]
except:
Matt Mackall
error: move UnexpectedOutput (now ResponseError)
r7641 raise error.ResponseError(_("unexpected response:"), d)
Matt Mackall
protocol: avoid sending outrageously large between requests
r7342 return r
mpm@selenic.com
Break apart hg.py...
r1089
Vadim Gelfer
add preoutgoing and outgoing hooks....
r1736 def changegroup(self, nodes, kind):
mpm@selenic.com
Break apart hg.py...
r1089 n = " ".join(map(hex, nodes))
f = self.do_cmd("changegroup", roots=n)
Matt Mackall
remove duplicate zgenerator in httprepo
r3661 return util.chunkbuffer(zgenerator(f))
Eric Hopper
Adding changegroupsubset and lookup to web protocol so pull -r and...
r3444
def changegroupsubset(self, bases, heads, source):
Bryan O'Sullivan
Push capability checking into protocol-level code.
r5259 self.requirecap('changegroupsubset', _('look up remote changes'))
Eric Hopper
Adding changegroupsubset and lookup to web protocol so pull -r and...
r3444 baselst = " ".join([hex(n) for n in bases])
headlst = " ".join([hex(n) for n in heads])
f = self.do_cmd("changegroupsubset", bases=baselst, heads=headlst)
Matt Mackall
remove duplicate zgenerator in httprepo
r3661 return util.chunkbuffer(zgenerator(f))
mpm@selenic.com
Break apart hg.py...
r1089
Vadim Gelfer
extend network protocol to stop clients from locking servers...
r2439 def unbundle(self, cg, heads, source):
Vadim Gelfer
push over http: client support....
r2465 # have to stream bundle to a temp file because we do not have
# http 1.1 chunked transfer.
Matt Mackall
unduplicate bundle writing code from httprepo
r3662 type = ""
types = self.capable('unbundle')
Alexis S. L. Carvalho
fix push over HTTP to older servers
r3703 # servers older than d1b16a746db6 will send 'unbundle' as a
# boolean capability
try:
types = types.split(',')
except AttributeError:
types = [""]
Matt Mackall
unduplicate bundle writing code from httprepo
r3662 if types:
Alexis S. L. Carvalho
fix push over HTTP to older servers
r3703 for x in types:
Matt Mackall
unduplicate bundle writing code from httprepo
r3662 if x in changegroup.bundletypes:
type = x
break
Thomas Arendsen Hein
Client support for hgweb unbundle with versions.
r3613
Matt Mackall
unduplicate bundle writing code from httprepo
r3662 tempname = changegroup.writebundle(cg, None, type)
Benoit Boissinot
factor out the url handling from httprepo...
r7270 fp = url.httpsendfile(tempname, "rb")
Vadim Gelfer
push over http: client support....
r2465 try:
try:
Benoit Boissinot
enhance the error output in case of failure during http push
r7010 resp = self.do_read(
'unbundle', data=fp,
headers={'Content-Type': 'application/octet-stream'},
heads=' '.join(map(hex, heads)))
resp_code, output = resp.split('\n', 1)
Vadim Gelfer
http client: better work with authorization errors, broken sockets.
r2467 try:
Benoit Boissinot
enhance the error output in case of failure during http push
r7010 ret = int(resp_code)
except ValueError, err:
Matt Mackall
error: move UnexpectedOutput (now ResponseError)
r7641 raise error.ResponseError(
Benoit Boissinot
enhance the error output in case of failure during http push
r7010 _('push failed (unexpected response):'), resp)
self.ui.write(output)
return ret
Vadim Gelfer
http client: better work with authorization errors, broken sockets.
r2467 except socket.error, err:
if err[0] in (errno.ECONNRESET, errno.EPIPE):
Thomas Arendsen Hein
Never apply string formatting to generated errors with util.Abort....
r3072 raise util.Abort(_('push failed: %s') % err[1])
Vadim Gelfer
http client: better work with authorization errors, broken sockets.
r2467 raise util.Abort(err[1])
Vadim Gelfer
push over http: client support....
r2465 finally:
fp.close()
os.unlink(tempname)
Vadim Gelfer
extend network protocol to stop clients from locking servers...
r2439
Vadim Gelfer
add support for streaming clone....
r2612 def stream_out(self):
return self.do_cmd('stream_out')
mpm@selenic.com
Break apart hg.py...
r1089 class httpsrepository(httprepository):
Alexis S. L. Carvalho
HTTPS: fix python2.3, persistent connections, don't explode if SSL is not available...
r2569 def __init__(self, ui, path):
Benoit Boissinot
Fix https availability checking...
r7279 if not url.has_https:
Alexis S. L. Carvalho
HTTPS: fix python2.3, persistent connections, don't explode if SSL is not available...
r2569 raise util.Abort(_('Python support for SSL and HTTPS '
'is not installed'))
httprepository.__init__(self, ui, path)
Vadim Gelfer
clean up hg.py: move repo constructor code into each repo module
r2740
def instance(ui, path, create):
if create:
raise util.Abort(_('cannot create new http repository'))
Matt Mackall
Autodetect static-http
r7211 try:
if path.startswith('https:'):
inst = httpsrepository(ui, path)
else:
inst = httprepository(ui, path)
inst.between([(nullid, nullid)])
return inst
Matt Mackall
error: move repo errors...
r7637 except error.RepoError:
Matt Mackall
Autodetect static-http
r7211 ui.note('(falling back to static-http)\n')
return statichttprepo.instance(ui, "static-" + path, create)