##// END OF EJS Templates
http: handle push of bundles > 2 GB again (issue3017)...
http: handle push of bundles > 2 GB again (issue3017) It was very elegant that httpsendfile implemented __len__ like a string. It was however also dangerous because that protocol can't handle sizes bigger than 2 GB. Mercurial tried to work around that, but it turned out to be too easy to introduce new errors in this area. With this change __len__ is no longer implemented at all and the code will work the same way for short and long posts.

File last commit:

r15152:94b200a1 stable
r15152:94b200a1 stable
Show More
httprepo.py
244 lines | 8.8 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 #
Martin Geisler
updated license to be explicit about GPL version 2
r8225 # This software may be used and distributed according to the terms of the
Matt Mackall
Update license to GPLv2+
r10263 # GNU General Public License version 2 or any later version.
mpm@selenic.com
Break apart hg.py...
r1089
Brodie Rao
cleanup: remove unused imports
r12062 from node import nullid
Matt Mackall
Simplify i18n imports
r3891 from i18n import _
Augie Fackler
url: use new http support if requested by the user...
r14244 import changegroup, statichttprepo, error, httpconnection, url, util, wireproto
Brodie Rao
httprepo/sshrepo: use url.url...
r13819 import os, urllib, urllib2, zlib, httplib
Simon Heimberg
separate import lines from mercurial and general python modules
r8312 import errno, socket
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):
Matt Mackall
httprepo: decompress stream incrementally to reduce memory usage
r11757 while chunk:
yield zd.decompress(chunk, 2**18)
chunk = zd.unconsumed_tail
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
protocol: unify basic http client requests
r11587 class httprepository(wireproto.wirerepository):
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
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 u = util.url(path)
Brodie Rao
httprepo/sshrepo: use url.url...
r13819 if u.query or u.fragment:
Vadim Gelfer
http: fix many problems with url parsing and auth. added proxy test....
r2337 raise util.Abort(_('unsupported URL component: "%s"') %
Brodie Rao
httprepo/sshrepo: use url.url...
r13819 (u.query or u.fragment))
Vadim Gelfer
http: fix many problems with url parsing and auth. added proxy test....
r2337
# urllib cannot handle URLs with embedded user or passwd
Brodie Rao
httprepo/sshrepo: use url.url...
r13819 self._url, authinfo = u.authinfo()
Benoit Boissinot
factor out the url handling from httprepo...
r7270
mpm@selenic.com
Break apart hg.py...
r1089 self.ui = ui
Martin Geisler
do not attempt to translate ui.debug output
r9467 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
Peter Arrenbrecht
httprepo: use caps instead of between for compat check...
r13603 def _fetchcaps(self):
self.caps = set(self._call('capabilities').split())
Vadim Gelfer
http: query server for capabilities
r2442 def get_caps(self):
if self.caps is None:
try:
Peter Arrenbrecht
httprepo: use caps instead of between for compat check...
r13603 self._fetchcaps()
Matt Mackall
error: move repo errors...
r7637 except error.RepoError:
Martin Geisler
util: use built-in set and frozenset...
r8150 self.caps = set()
Martin Geisler
do not attempt to translate ui.debug output
r9467 self.ui.debug('capabilities: %s\n' %
Vadim Gelfer
push over http: client support....
r2465 (' '.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'))
Matt Mackall
protocol: clean up call-like functions in http and ssh clients
r11589 def _callstream(self, cmd, **args):
Dan Villiom Podlaski Christiansen
httprepo: remove is-comparison with string literal...
r13006 if cmd == 'pushkey':
Matt Mackall
pushkey: force HTTP POST on push and add tests (issue2489)
r12969 args['data'] = ''
Vadim Gelfer
push over http: client support....
r2465 data = args.pop('data', None)
Mads Kiilerich
http: handle push of bundles > 2 GB again (issue3017)...
r15152 size = 0
if util.safehasattr(data, 'length'):
size = data.length
elif data is not None:
size = len(data)
Vadim Gelfer
push over http: client support....
r2465 headers = args.pop('headers', {})
Augie Fackler
httprepo: send 100-continue on POSTs if using http2
r14245
Mads Kiilerich
http: handle push of bundles > 2 GB again (issue3017)...
r15152 if size and self.ui.configbool('ui', 'usehttp2', False):
Augie Fackler
httprepo: send 100-continue on POSTs if using http2
r14245 headers['Expect'] = '100-Continue'
Augie Fackler
http2: send an extra header to signal a non-broken client...
r14991 headers['X-HgHttp2'] = '1'
Augie Fackler
httprepo: send 100-continue on POSTs if using http2
r14245
Martin Geisler
do not attempt to translate ui.debug output
r9467 self.ui.debug("sending %s command\n" % cmd)
Steven Brown
httprepo: long arguments support (issue2126)...
r14093 q = [('cmd', cmd)]
headersize = 0
if len(args) > 0:
httpheader = self.capable('httpheader')
if httpheader:
headersize = int(httpheader.split(',')[0])
if headersize > 0:
# The headers can typically carry more data than the URL.
encargs = urllib.urlencode(sorted(args.items()))
Matt Mackall
http: minor tweaks to long arg handling...
r14094 headerfmt = 'X-HgArg-%s'
Steven Brown
httprepo: long arguments support (issue2126)...
r14093 contentlen = headersize - len(headerfmt % '000' + ': \r\n')
headernum = 0
for i in xrange(0, len(encargs), contentlen):
headernum += 1
header = headerfmt % str(headernum)
headers[header] = encargs[i:i + contentlen]
varyheaders = [headerfmt % str(h) for h in range(1, headernum + 1)]
headers['Vary'] = ','.join(varyheaders)
else:
q += sorted(args.items())
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)
Benoit Boissinot
http: len(x) fails if it doesn't fit into an int, use __len__() instead...
r10491 req = urllib2.Request(cu, data, headers)
if data is not None:
self.ui.debug("sending %s bytes\n" % size)
req.add_unredirected_header('Content-Length', '%d' % size)
Thomas Arendsen Hein
Catch urllib's HTTPException and give a meaningful error message to the user....
r2294 try:
Benoit Boissinot
http: len(x) fails if it doesn't fit into an int, use __len__() instead...
r10491 resp = self.urlopener.open(req)
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:
Martin Geisler
do not attempt to translate ui.debug output
r9467 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)]
Dan Villiom Podlaski Christiansen
httprepo: suppress the `real URL is...' message in safe, common cases....
r9881 if self._url.rstrip('/') != resp_url.rstrip('/'):
Matt Mackall
httprepo: send URL redirection notices to stderr (issue2828)
r14504 if not self.ui.quiet:
self.ui.warn(_('real URL is %s\n') % resp_url)
Steve Borho
httprepo: always store the response url (issue1968)...
r10208 self._url = resp_url
Vadim Gelfer
http client: support persistent connections....
r2435 try:
proto = resp.getheader('content-type')
except AttributeError:
Mads Kiilerich
httprepo: proper handling of invalid responses without content-type (issue2019)...
r14503 proto = resp.headers.get('content-type', '')
mpm@selenic.com
Break apart hg.py...
r1089
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 safeurl = util.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')):
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 self.ui.debug("requested URL: '%s'\n" % util.hidepassword(cu))
Matt Mackall
many, many trivial check-code fixups
r10282 raise error.RepoError(
_("'%s' does not appear to be an hg repository:\n"
"---%%<--- (%s)\n%s\n---%%<---\n")
Mads Kiilerich
httprepo: proper handling of invalid responses without content-type (issue2019)...
r14503 % (safeurl, proto or 'no content-type', resp.read()))
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
Matt Mackall
protocol: clean up call-like functions in http and ssh clients
r11589 def _call(self, cmd, **args):
fp = self._callstream(cmd, **args)
Vadim Gelfer
http client: support persistent connections....
r2435 try:
return fp.read()
finally:
# if using keepalive, allow connection to be reused
fp.close()
Matt Mackall
protocol: unify client unbundle support...
r11592 def _callpush(self, cmd, cg, **args):
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 types = self.capable('unbundle')
Alexis S. L. Carvalho
fix push over HTTP to older servers
r3703 try:
types = types.split(',')
except AttributeError:
Benoit Boissinot
bundle: more comments about the different header types, remove useless if
r14060 # servers older than d1b16a746db6 will send 'unbundle' as a
# boolean capability. They only support headerless/uncompressed
# bundles.
Alexis S. L. Carvalho
fix push over HTTP to older servers
r3703 types = [""]
Benoit Boissinot
bundle: more comments about the different header types, remove useless if
r14060 for x in types:
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)
Augie Fackler
url: use new http support if requested by the user...
r14244 fp = httpconnection.httpsendfile(self.ui, tempname, "rb")
Matt Mackall
protocol: unify client unbundle support...
r11592 headers = {'Content-Type': 'application/mercurial-0.1'}
Vadim Gelfer
push over http: client support....
r2465 try:
try:
Matt Mackall
protocol: unify client unbundle support...
r11592 r = self._call(cmd, data=fp, headers=headers, **args)
Matt Mackall
http: report unexpected unparsable push responses (issue2777)
r14641 vals = r.split('\n', 1)
if len(vals) < 2:
Matt Mackall
http: fix variable name in unexpected response message
r14648 raise error.ResponseError(_("unexpected response:"), r)
Matt Mackall
http: report unexpected unparsable push responses (issue2777)
r14641 return vals
Vadim Gelfer
http client: better work with authorization errors, broken sockets.
r2467 except socket.error, err:
Renato Cunha
removed exception args indexing (not supported by py3k)...
r11567 if err.args[0] in (errno.ECONNRESET, errno.EPIPE):
raise util.Abort(_('push failed: %s') % err.args[1])
raise util.Abort(err.args[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
Matt Mackall
protocol: unify client unbundle support...
r11592 def _abort(self, exception):
raise exception
Vadim Gelfer
add support for streaming clone....
r2612
Matt Mackall
protocol: unify client unbundle support...
r11592 def _decompress(self, stream):
return util.chunkbuffer(zgenerator(stream))
Matt Mackall
pushkey: add http support...
r11370
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)
Peter Arrenbrecht
httprepo: use caps instead of between for compat check...
r13603 try:
# Try to do useful work when checking compatibility.
# Usually saves a roundtrip since we want the caps anyway.
inst._fetchcaps()
except error.RepoError:
# No luck, try older compatibility check.
inst.between([(nullid, nullid)])
Matt Mackall
Autodetect static-http
r7211 return inst
Mads Kiilerich
httprepo: use the original exception after falling back to static-http failed...
r14148 except error.RepoError, httpexception:
try:
r = statichttprepo.instance(ui, "static-" + path, create)
ui.note('(falling back to static-http)\n')
return r
except error.RepoError:
raise httpexception # use the original http RepoError instead