diff --git a/.hgsigs b/.hgsigs --- a/.hgsigs +++ b/.hgsigs @@ -158,3 +158,5 @@ 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 diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -171,3 +171,5 @@ cabc840ffdee8a72f3689fb77dd74d04fdc2bc04 a92b9f8e11ba330614cdfd6af0e03b15c1ff3797 4.4.2 27b6df1b5adbdf647cf5c6675b40575e1b197c60 4.5-rc d334afc585e29577f271c5eda03378736a16ca6b 4.5 +369aadf7a3264b03c8b09efce715bc41e6ab4a9b 4.5.1 +8bba684efde7f45add05f737952093bb2aa07155 4.5.2 diff --git a/hgext/largefiles/uisetup.py b/hgext/largefiles/uisetup.py --- a/hgext/largefiles/uisetup.py +++ b/hgext/largefiles/uisetup.py @@ -12,7 +12,6 @@ from __future__ import absolute_import from mercurial.i18n import _ from mercurial.hgweb import ( - hgweb_mod, webcommands, ) @@ -175,9 +174,10 @@ def uisetup(ui): # make putlfile behave the same as push and {get,stat}lfile behave # the same as pull w.r.t. permissions checks - hgweb_mod.perms['putlfile'] = 'push' - hgweb_mod.perms['getlfile'] = 'pull' - hgweb_mod.perms['statlfile'] = 'pull' + wireproto.permissions['putlfile'] = 'push' + wireproto.permissions['getlfile'] = 'pull' + wireproto.permissions['statlfile'] = 'pull' + wireproto.permissions['lheads'] = 'pull' extensions.wrapfunction(webcommands, 'decodepath', overrides.decodepath) diff --git a/mercurial/changegroup.py b/mercurial/changegroup.py --- a/mercurial/changegroup.py +++ b/mercurial/changegroup.py @@ -774,6 +774,8 @@ class cg1packer(object): progress(msgbundling, None) def deltaparent(self, revlog, rev, p1, p2, prev): + if not revlog.candelta(prev, rev): + raise error.ProgrammingError('cg1 should not be used in this case') return prev def revchunk(self, revlog, rev, prev, linknode): @@ -833,16 +835,19 @@ class cg2packer(cg1packer): # expensive. The revlog caches should have prev cached, meaning # less CPU for changegroup generation. There is likely room to add # a flag and/or config option to control this behavior. - return prev + base = prev elif dp == nullrev: # revlog is configured to use full snapshot for a reason, # stick to full snapshot. - return nullrev + base = nullrev elif dp not in (p1, p2, prev): # Pick prev when we can't be sure remote has the base revision. return prev else: - return dp + base = dp + if base != nullrev and not revlog.candelta(base, rev): + base = nullrev + return base def builddeltaheader(self, node, p1n, p2n, basenode, linknode, flags): # Do nothing with flags, it is implicitly 0 in cg1 and cg2 diff --git a/mercurial/hgweb/hgweb_mod.py b/mercurial/hgweb/hgweb_mod.py --- a/mercurial/hgweb/hgweb_mod.py +++ b/mercurial/hgweb/hgweb_mod.py @@ -37,6 +37,7 @@ from .. import ( templater, ui as uimod, util, + wireproto, wireprotoserver, ) @@ -46,15 +47,8 @@ from . import ( wsgicgi, ) -perms = { - 'changegroup': 'pull', - 'changegroupsubset': 'pull', - 'getbundle': 'pull', - 'stream_out': 'pull', - 'listkeys': 'pull', - 'unbundle': 'push', - 'pushkey': 'push', -} +# Aliased for API compatibility. +perms = wireproto.permissions archivespecs = util.sortdict(( ('zip', ('application/zip', 'zip', '.zip', None)), @@ -367,13 +361,21 @@ class hgweb(object): try: if query: raise ErrorResponse(HTTP_NOT_FOUND) - if cmd in perms: - self.check_perm(rctx, req, perms[cmd]) + + # TODO fold this into parsehttprequest + req.checkperm = lambda op: self.check_perm(rctx, req, op) + protohandler['proto'].checkperm = req.checkperm + + # Assume commands with no defined permissions are writes / + # for pushes. This is the safest from a security perspective + # because it doesn't allow commands with undefined semantics + # from bypassing permissions checks. + req.checkperm(perms.get(cmd, 'push')) + + return protohandler['dispatch']() except ErrorResponse as inst: return protohandler['handleerror'](inst) - return protohandler['dispatch']() - # translate user-visible url structure to internal structure args = query.split('/', 2) diff --git a/mercurial/revlog.py b/mercurial/revlog.py --- a/mercurial/revlog.py +++ b/mercurial/revlog.py @@ -77,6 +77,8 @@ REVIDX_FLAGS_ORDER = [ REVIDX_EXTSTORED, ] REVIDX_KNOWN_FLAGS = util.bitsfrom(REVIDX_FLAGS_ORDER) +# bitmark for flags that could cause rawdata content change +REVIDX_RAWTEXT_CHANGING_FLAGS = REVIDX_ISCENSORED | REVIDX_EXTSTORED # max size of revlog with inline data _maxinline = 131072 @@ -96,7 +98,8 @@ def addflagprocessor(flag, processor): """Register a flag processor on a revision data flag. Invariant: - - Flags need to be defined in REVIDX_KNOWN_FLAGS and REVIDX_FLAGS_ORDER. + - Flags need to be defined in REVIDX_KNOWN_FLAGS and REVIDX_FLAGS_ORDER, + and REVIDX_RAWTEXT_CHANGING_FLAGS if they can alter rawtext. - Only one flag processor can be registered on a specific flag. - flagprocessors must be 3-tuples of functions (read, write, raw) with the following signatures: @@ -333,7 +336,9 @@ class _deltacomputer(object): len(delta) - hlen): btext[0] = delta[hlen:] else: - basetext = revlog.revision(baserev, _df=fh, raw=True) + # deltabase is rawtext before changed by flag processors, which is + # equivalent to non-raw text + basetext = revlog.revision(baserev, _df=fh, raw=False) btext[0] = mdiff.patch(basetext, delta) try: @@ -404,6 +409,9 @@ class _deltacomputer(object): for candidaterevs in self._getcandidaterevs(p1, p2, cachedelta): nominateddeltas = [] for candidaterev in candidaterevs: + # no delta for rawtext-changing revs (see "candelta" for why) + if revlog.flags(candidaterev) & REVIDX_RAWTEXT_CHANGING_FLAGS: + continue candidatedelta = self._builddeltainfo(revinfo, candidaterev, fh) if revlog._isgooddeltainfo(candidatedelta, revinfo.textlen): nominateddeltas.append(candidatedelta) @@ -738,6 +746,18 @@ class revlog(object): except KeyError: return False + def candelta(self, baserev, rev): + """whether two revisions (baserev, rev) can be delta-ed or not""" + # Disable delta if either rev requires a content-changing flag + # processor (ex. LFS). This is because such flag processor can alter + # the rawtext content that the delta will be based on, and two clients + # could have a same revlog node with different flags (i.e. different + # rawtext contents) and the delta could be incompatible. + if ((self.flags(baserev) & REVIDX_RAWTEXT_CHANGING_FLAGS) + or (self.flags(rev) & REVIDX_RAWTEXT_CHANGING_FLAGS)): + return False + return True + def clearcaches(self): self._cache = None self._chainbasecache.clear() @@ -2078,7 +2098,10 @@ class revlog(object): # full versions are inserted when the needed deltas # become comparable to the uncompressed text if rawtext is None: - textlen = mdiff.patchedsize(self.rawsize(cachedelta[0]), + # need rawtext size, before changed by flag processors, which is + # the non-raw size. use revlog explicitly to avoid filelog's extra + # logic that might remove metadata size. + textlen = mdiff.patchedsize(revlog.size(self, cachedelta[0]), cachedelta[1]) else: textlen = len(rawtext) @@ -2087,7 +2110,14 @@ class revlog(object): deltacomputer = _deltacomputer(self) revinfo = _revisioninfo(node, p1, p2, btext, textlen, cachedelta, flags) - deltainfo = deltacomputer.finddeltainfo(revinfo, fh) + + # no delta for flag processor revision (see "candelta" for why) + # not calling candelta since only one revision needs test, also to + # avoid overhead fetching flags again. + if flags & REVIDX_RAWTEXT_CHANGING_FLAGS: + deltainfo = None + else: + deltainfo = deltacomputer.finddeltainfo(revinfo, fh) if deltainfo is not None: base = deltainfo.base diff --git a/mercurial/wireproto.py b/mercurial/wireproto.py --- a/mercurial/wireproto.py +++ b/mercurial/wireproto.py @@ -672,6 +672,11 @@ POLICY_V2_ONLY = 'v2-only' commands = commanddict() +# Maps wire protocol name to operation type. This is used for permissions +# checking. All defined @wireiprotocommand should have an entry in this +# dict. +permissions = {} + def wireprotocommand(name, args='', transportpolicy=POLICY_ALL): """Decorator to declare a wire protocol command. @@ -701,6 +706,8 @@ def wireprotocommand(name, args='', tran return func return register +# TODO define a more appropriate permissions type to use for this. +permissions['batch'] = 'pull' @wireprotocommand('batch', 'cmds *') def batch(repo, proto, cmds, others): repo = repo.filtered("served") @@ -713,6 +720,17 @@ def batch(repo, proto, cmds, others): n, v = a.split('=') vals[unescapearg(n)] = unescapearg(v) func, spec = commands[op] + + # If the protocol supports permissions checking, perform that + # checking on each batched command. + # TODO formalize permission checking as part of protocol interface. + if util.safehasattr(proto, 'checkperm'): + # Assume commands with no defined permissions are writes / for + # pushes. This is the safest from a security perspective because + # it doesn't allow commands with undefined semantics from + # bypassing permissions checks. + proto.checkperm(permissions.get(op, 'push')) + if spec: keys = spec.split() data = {} @@ -740,6 +758,7 @@ def batch(repo, proto, cmds, others): return bytesresponse(';'.join(res)) +permissions['between'] = 'pull' @wireprotocommand('between', 'pairs', transportpolicy=POLICY_V1_ONLY) def between(repo, proto, pairs): pairs = [decodelist(p, '-') for p in pairs.split(" ")] @@ -749,6 +768,7 @@ def between(repo, proto, pairs): return bytesresponse(''.join(r)) +permissions['branchmap'] = 'pull' @wireprotocommand('branchmap') def branchmap(repo, proto): branchmap = repo.branchmap() @@ -760,6 +780,7 @@ def branchmap(repo, proto): return bytesresponse('\n'.join(heads)) +permissions['branches'] = 'pull' @wireprotocommand('branches', 'nodes', transportpolicy=POLICY_V1_ONLY) def branches(repo, proto, nodes): nodes = decodelist(nodes) @@ -769,6 +790,7 @@ def branches(repo, proto, nodes): return bytesresponse(''.join(r)) +permissions['clonebundles'] = 'pull' @wireprotocommand('clonebundles', '') def clonebundles(repo, proto): """Server command for returning info for available bundles to seed clones. @@ -821,10 +843,12 @@ def _capabilities(repo, proto): # If you are writing an extension and consider wrapping this function. Wrap # `_capabilities` instead. +permissions['capabilities'] = 'pull' @wireprotocommand('capabilities') def capabilities(repo, proto): return bytesresponse(' '.join(_capabilities(repo, proto))) +permissions['changegroup'] = 'pull' @wireprotocommand('changegroup', 'roots', transportpolicy=POLICY_V1_ONLY) def changegroup(repo, proto, roots): nodes = decodelist(roots) @@ -834,6 +858,7 @@ def changegroup(repo, proto, roots): gen = iter(lambda: cg.read(32768), '') return streamres(gen=gen) +permissions['changegroupsubset'] = 'pull' @wireprotocommand('changegroupsubset', 'bases heads', transportpolicy=POLICY_V1_ONLY) def changegroupsubset(repo, proto, bases, heads): @@ -845,6 +870,7 @@ def changegroupsubset(repo, proto, bases gen = iter(lambda: cg.read(32768), '') return streamres(gen=gen) +permissions['debugwireargs'] = 'pull' @wireprotocommand('debugwireargs', 'one two *') def debugwireargs(repo, proto, one, two, others): # only accept optional args from the known set @@ -852,6 +878,7 @@ def debugwireargs(repo, proto, one, two, return bytesresponse(repo.debugwireargs(one, two, **pycompat.strkwargs(opts))) +permissions['getbundle'] = 'pull' @wireprotocommand('getbundle', '*') def getbundle(repo, proto, others): opts = options('getbundle', gboptsmap.keys(), others) @@ -918,11 +945,13 @@ def getbundle(repo, proto, others): return streamres(gen=chunks, prefer_uncompressed=not prefercompressed) +permissions['heads'] = 'pull' @wireprotocommand('heads') def heads(repo, proto): h = repo.heads() return bytesresponse(encodelist(h) + '\n') +permissions['hello'] = 'pull' @wireprotocommand('hello') def hello(repo, proto): """Called as part of SSH handshake to obtain server info. @@ -938,11 +967,13 @@ def hello(repo, proto): caps = capabilities(repo, proto).data return bytesresponse('capabilities: %s\n' % caps) +permissions['listkeys'] = 'pull' @wireprotocommand('listkeys', 'namespace') def listkeys(repo, proto, namespace): d = sorted(repo.listkeys(encoding.tolocal(namespace)).items()) return bytesresponse(pushkeymod.encodekeys(d)) +permissions['lookup'] = 'pull' @wireprotocommand('lookup', 'key') def lookup(repo, proto, key): try: @@ -955,11 +986,13 @@ def lookup(repo, proto, key): success = 0 return bytesresponse('%d %s\n' % (success, r)) +permissions['known'] = 'pull' @wireprotocommand('known', 'nodes *') def known(repo, proto, nodes, others): v = ''.join(b and '1' or '0' for b in repo.known(decodelist(nodes))) return bytesresponse(v) +permissions['pushkey'] = 'push' @wireprotocommand('pushkey', 'namespace key old new') def pushkey(repo, proto, namespace, key, old, new): # compatibility with pre-1.8 clients which were accidentally @@ -981,6 +1014,7 @@ def pushkey(repo, proto, namespace, key, output = output.getvalue() if output else '' return bytesresponse('%d\n%s' % (int(r), output)) +permissions['stream_out'] = 'pull' @wireprotocommand('stream_out') def stream(repo, proto): '''If the server supports streaming clone, it advertises the "stream" @@ -989,6 +1023,7 @@ def stream(repo, proto): ''' return streamres_legacy(streamclone.generatev1wireproto(repo)) +permissions['unbundle'] = 'push' @wireprotocommand('unbundle', 'heads') def unbundle(repo, proto, heads): their_heads = decodelist(heads) diff --git a/tests/drawdag.py b/tests/drawdag.py --- a/tests/drawdag.py +++ b/tests/drawdag.py @@ -371,7 +371,8 @@ def debugdrawdag(ui, repo, **opts): comments = list(_getcomments(text)) filere = re.compile(br'^(\w+)/([\w/]+)\s*=\s*(.*)$', re.M) for name, path, content in filere.findall(b'\n'.join(comments)): - files[name][path] = content.replace(br'\n', b'\n') + content = content.replace(br'\n', b'\n').replace(br'\1', b'\1') + files[name][path] = content committed = {None: node.nullid} # {name: node} diff --git a/tests/test-annotate.t b/tests/test-annotate.t --- a/tests/test-annotate.t +++ b/tests/test-annotate.t @@ -903,9 +903,15 @@ Annotate with orphaned CR (issue5798) $ hg init repo-cr $ cd repo-cr - $ substcr() { - > sed 's/\r/[CR]/g' - > } + $ cat <<'EOF' >> "$TESTTMP/substcr.py" + > import sys + > from mercurial import util + > util.setbinary(sys.stdin) + > util.setbinary(sys.stdout) + > stdin = getattr(sys.stdin, 'buffer', sys.stdin) + > stdout = getattr(sys.stdout, 'buffer', sys.stdout) + > stdout.write(stdin.read().replace(b'\r', b'[CR]')) + > EOF >>> with open('a', 'wb') as f: ... f.write(b'0a\r0b\r\n0c\r0d\r\n0e\n0f\n0g') @@ -914,13 +920,13 @@ Annotate with orphaned CR (issue5798) ... f.write(b'0a\r0b\r\n1c\r1d\r\n0e\n1f\n0g') $ hg ci -m1 - $ hg annotate -r0 a | substcr + $ hg annotate -r0 a | $PYTHON "$TESTTMP/substcr.py" 0: 0a[CR]0b[CR] 0: 0c[CR]0d[CR] 0: 0e 0: 0f 0: 0g - $ hg annotate -r1 a | substcr + $ hg annotate -r1 a | $PYTHON "$TESTTMP/substcr.py" 0: 0a[CR]0b[CR] 1: 1c[CR]1d[CR] 0: 0e diff --git a/tests/test-http-bundle1.t b/tests/test-http-bundle1.t --- a/tests/test-http-bundle1.t +++ b/tests/test-http-bundle1.t @@ -260,60 +260,52 @@ test http authentication $ hg rollback -q $ sed 's/.*] "/"/' < ../access.log - "GET /?cmd=capabilities HTTP/1.1" 200 - - "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ - "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ + "GET /?cmd=capabilities HTTP/1.1" 401 - + "GET /?cmd=capabilities HTTP/1.1" 401 - + "GET /?cmd=capabilities HTTP/1.1" 401 - "GET /?cmd=capabilities HTTP/1.1" 200 - "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ - "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ + "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ + "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ + "GET /?cmd=capabilities HTTP/1.1" 401 - "GET /?cmd=capabilities HTTP/1.1" 200 - "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ - "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ - "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ - "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ - "GET /?cmd=capabilities HTTP/1.1" 200 - - "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ - "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ + "GET /?cmd=capabilities HTTP/1.1" 401 - "GET /?cmd=capabilities HTTP/1.1" 200 - "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ - "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ + "GET /?cmd=capabilities HTTP/1.1" 401 - "GET /?cmd=capabilities HTTP/1.1" 200 - "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ - "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ + "GET /?cmd=capabilities HTTP/1.1" 401 - "GET /?cmd=capabilities HTTP/1.1" 200 - "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ - "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ + "GET /?cmd=capabilities HTTP/1.1" 401 - "GET /?cmd=capabilities HTTP/1.1" 200 - "GET /?cmd=branchmap HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ - "GET /?cmd=stream_out HTTP/1.1" 401 - x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ "GET /?cmd=stream_out HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D5fed3813f7f5e1824344fdc9cf8f63bb662c292d x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ + "GET /?cmd=capabilities HTTP/1.1" 401 - "GET /?cmd=capabilities HTTP/1.1" 200 - - "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ "GET /?cmd=getbundle HTTP/1.1" 200 - x-hgarg-1:common=0000000000000000000000000000000000000000&heads=5fed3813f7f5e1824344fdc9cf8f63bb662c292d x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ - "GET /?cmd=capabilities HTTP/1.1" 200 - - "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ - "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ - "GET /?cmd=capabilities HTTP/1.1" 200 - - "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ - "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ - "GET /?cmd=listkeys HTTP/1.1" 403 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ + "GET /?cmd=capabilities HTTP/1.1" 401 - + "GET /?cmd=capabilities HTTP/1.1" 401 - + "GET /?cmd=capabilities HTTP/1.1" 403 - + "GET /?cmd=capabilities HTTP/1.1" 401 - "GET /?cmd=capabilities HTTP/1.1" 200 - "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D7f4e523d01f2cc3765ac8934da3d14db775ff872 x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ - "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ "GET /?cmd=branchmap HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ diff --git a/tests/test-http-permissions.t b/tests/test-http-permissions.t new file mode 100644 --- /dev/null +++ b/tests/test-http-permissions.t @@ -0,0 +1,1502 @@ +#require killdaemons + + $ cat > fakeremoteuser.py << EOF + > import os + > from mercurial.hgweb import hgweb_mod + > from mercurial import wireproto + > class testenvhgweb(hgweb_mod.hgweb): + > def __call__(self, env, respond): + > # Allow REMOTE_USER to define authenticated user. + > if r'REMOTE_USER' in os.environ: + > env[r'REMOTE_USER'] = os.environ[r'REMOTE_USER'] + > # Allow REQUEST_METHOD to override HTTP method + > if r'REQUEST_METHOD' in os.environ: + > env[r'REQUEST_METHOD'] = os.environ[r'REQUEST_METHOD'] + > return super(testenvhgweb, self).__call__(env, respond) + > hgweb_mod.hgweb = testenvhgweb + > + > @wireproto.wireprotocommand('customreadnoperm') + > def customread(repo, proto): + > return b'read-only command no defined permissions\n' + > @wireproto.wireprotocommand('customwritenoperm') + > def customwritenoperm(repo, proto): + > return b'write command no defined permissions\n' + > wireproto.permissions['customreadwithperm'] = 'pull' + > @wireproto.wireprotocommand('customreadwithperm') + > def customreadwithperm(repo, proto): + > return b'read-only command w/ defined permissions\n' + > wireproto.permissions['customwritewithperm'] = 'push' + > @wireproto.wireprotocommand('customwritewithperm') + > def customwritewithperm(repo, proto): + > return b'write command w/ defined permissions\n' + > EOF + + $ cat >> $HGRCPATH << EOF + > [extensions] + > fakeremoteuser = $TESTTMP/fakeremoteuser.py + > strip = + > EOF + + $ hg init test + $ cd test + $ echo a > a + $ hg ci -Ama + adding a + $ cd .. + $ hg clone test test2 + updating to branch default + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ cd test2 + $ echo a >> a + $ hg ci -mb + $ hg book bm -r 0 + $ cd ../test + +web.deny_read=* prevents access to wire protocol for all users + + $ cat > .hg/hgrc < [web] + > deny_read = * + > EOF + + $ hg serve -p $HGPORT -d --pid-file hg.pid + $ cat hg.pid > $DAEMON_PIDS + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=capabilities' + 401 read not authorized + + 0 + read not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=stream_out' + 401 read not authorized + + 0 + read not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases' + 401 read not authorized + + 0 + read not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases' + 401 read not authorized + + 0 + read not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm' + 401 read not authorized + + 0 + read not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm' + 401 read not authorized + + 0 + read not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm' + 401 read not authorized + + 0 + read not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm' + 401 read not authorized + + 0 + read not authorized + [1] + + $ hg --cwd ../test2 pull http://localhost:$HGPORT/ + pulling from http://localhost:$HGPORT/ + abort: authorization failed + [255] + + $ killdaemons.py + +web.deny_read=* with REMOTE_USER set still locks out clients + + $ REMOTE_USER=authed_user hg serve -p $HGPORT -d --pid-file hg.pid + $ cat hg.pid > $DAEMON_PIDS + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=capabilities' + 401 read not authorized + + 0 + read not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=stream_out' + 401 read not authorized + + 0 + read not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases' + 401 read not authorized + + 0 + read not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm' + 401 read not authorized + + 0 + read not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm' + 401 read not authorized + + 0 + read not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm' + 401 read not authorized + + 0 + read not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm' + 401 read not authorized + + 0 + read not authorized + [1] + + $ hg --cwd ../test2 pull http://localhost:$HGPORT/ + pulling from http://localhost:$HGPORT/ + abort: authorization failed + [255] + + $ killdaemons.py + +web.deny_read= denies access to unauthenticated user + + $ cat > .hg/hgrc < [web] + > deny_read = baduser1,baduser2 + > EOF + + $ hg serve -p $HGPORT -d --pid-file hg.pid + $ cat hg.pid > $DAEMON_PIDS + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases' + 401 read not authorized + + 0 + read not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases' + 401 read not authorized + + 0 + read not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm' + 401 read not authorized + + 0 + read not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm' + 401 read not authorized + + 0 + read not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm' + 401 read not authorized + + 0 + read not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm' + 401 read not authorized + + 0 + read not authorized + [1] + + $ hg --cwd ../test2 pull http://localhost:$HGPORT/ + pulling from http://localhost:$HGPORT/ + abort: authorization failed + [255] + + $ killdaemons.py + +web.deny_read= denies access to users in deny list + + $ REMOTE_USER=baduser2 hg serve -p $HGPORT -d --pid-file hg.pid + $ cat hg.pid > $DAEMON_PIDS + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases' + 401 read not authorized + + 0 + read not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases' + 401 read not authorized + + 0 + read not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm' + 401 read not authorized + + 0 + read not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm' + 401 read not authorized + + 0 + read not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm' + 401 read not authorized + + 0 + read not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm' + 401 read not authorized + + 0 + read not authorized + [1] + + $ hg --cwd ../test2 pull http://localhost:$HGPORT/ + pulling from http://localhost:$HGPORT/ + abort: authorization failed + [255] + + $ killdaemons.py + +web.deny_read= allows access to authenticated users not in list + + $ REMOTE_USER=gooduser hg serve -p $HGPORT -d --pid-file hg.pid + $ cat hg.pid > $DAEMON_PIDS + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases' + 200 Script output follows + + cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b 1 + publishing True (no-eol) + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases' + 200 Script output follows + + cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b 1 + publishing True (no-eol) + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm' + 405 push requires POST request + + 0 + push requires POST request + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm' + 200 Script output follows + + read-only command w/ defined permissions + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm' + 405 push requires POST request + + 0 + push requires POST request + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm' + 405 push requires POST request + + 0 + push requires POST request + [1] + + $ hg --cwd ../test2 pull http://localhost:$HGPORT/ + pulling from http://localhost:$HGPORT/ + searching for changes + no changes found + + $ killdaemons.py + +web.allow_read=* allows reads for unauthenticated users + + $ cat > .hg/hgrc < [web] + > allow_read = * + > EOF + + $ hg serve -p $HGPORT -d --pid-file hg.pid + $ cat hg.pid > $DAEMON_PIDS + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases' + 200 Script output follows + + cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b 1 + publishing True (no-eol) + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases' + 200 Script output follows + + cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b 1 + publishing True (no-eol) + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm' + 405 push requires POST request + + 0 + push requires POST request + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm' + 200 Script output follows + + read-only command w/ defined permissions + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm' + 405 push requires POST request + + 0 + push requires POST request + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm' + 405 push requires POST request + + 0 + push requires POST request + [1] + + $ hg --cwd ../test2 pull http://localhost:$HGPORT/ + pulling from http://localhost:$HGPORT/ + searching for changes + no changes found + + $ killdaemons.py + +web.allow_read=* allows read for authenticated user + + $ REMOTE_USER=authed_user hg serve -p $HGPORT -d --pid-file hg.pid + $ cat hg.pid > $DAEMON_PIDS + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases' + 200 Script output follows + + cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b 1 + publishing True (no-eol) + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases' + 200 Script output follows + + cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b 1 + publishing True (no-eol) + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm' + 405 push requires POST request + + 0 + push requires POST request + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm' + 200 Script output follows + + read-only command w/ defined permissions + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm' + 405 push requires POST request + + 0 + push requires POST request + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm' + 405 push requires POST request + + 0 + push requires POST request + [1] + + $ hg --cwd ../test2 pull http://localhost:$HGPORT/ + pulling from http://localhost:$HGPORT/ + searching for changes + no changes found + + $ killdaemons.py + +web.allow_read= does not allow unauthenticated users to read + + $ cat > .hg/hgrc < [web] + > allow_read = gooduser + > EOF + + $ hg serve -p $HGPORT -d --pid-file hg.pid + $ cat hg.pid > $DAEMON_PIDS + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases' + 401 read not authorized + + 0 + read not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases' + 401 read not authorized + + 0 + read not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm' + 401 read not authorized + + 0 + read not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm' + 401 read not authorized + + 0 + read not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm' + 401 read not authorized + + 0 + read not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm' + 401 read not authorized + + 0 + read not authorized + [1] + + $ hg --cwd ../test2 pull http://localhost:$HGPORT/ + pulling from http://localhost:$HGPORT/ + abort: authorization failed + [255] + + $ killdaemons.py + +web.allow_read= does not allow user not in list to read + + $ REMOTE_USER=baduser hg serve -p $HGPORT -d --pid-file hg.pid + $ cat hg.pid > $DAEMON_PIDS + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases' + 401 read not authorized + + 0 + read not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases' + 401 read not authorized + + 0 + read not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm' + 401 read not authorized + + 0 + read not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm' + 401 read not authorized + + 0 + read not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm' + 401 read not authorized + + 0 + read not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm' + 401 read not authorized + + 0 + read not authorized + [1] + + $ hg --cwd ../test2 pull http://localhost:$HGPORT/ + pulling from http://localhost:$HGPORT/ + abort: authorization failed + [255] + + $ killdaemons.py + +web.allow_read= allows read from user in list + + $ REMOTE_USER=gooduser hg serve -p $HGPORT -d --pid-file hg.pid + $ cat hg.pid > $DAEMON_PIDS + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases' + 200 Script output follows + + cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b 1 + publishing True (no-eol) + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases' + 200 Script output follows + + cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b 1 + publishing True (no-eol) + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm' + 405 push requires POST request + + 0 + push requires POST request + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm' + 200 Script output follows + + read-only command w/ defined permissions + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm' + 405 push requires POST request + + 0 + push requires POST request + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm' + 405 push requires POST request + + 0 + push requires POST request + [1] + + $ hg --cwd ../test2 pull http://localhost:$HGPORT/ + pulling from http://localhost:$HGPORT/ + searching for changes + no changes found + + $ killdaemons.py + +web.deny_read takes precedence over web.allow_read + + $ cat > .hg/hgrc < [web] + > allow_read = baduser + > deny_read = baduser + > EOF + + $ REMOTE_USER=baduser hg serve -p $HGPORT -d --pid-file hg.pid + $ cat hg.pid > $DAEMON_PIDS + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases' + 401 read not authorized + + 0 + read not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases' + 401 read not authorized + + 0 + read not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm' + 401 read not authorized + + 0 + read not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm' + 401 read not authorized + + 0 + read not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm' + 401 read not authorized + + 0 + read not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm' + 401 read not authorized + + 0 + read not authorized + [1] + + $ hg --cwd ../test2 pull http://localhost:$HGPORT/ + pulling from http://localhost:$HGPORT/ + abort: authorization failed + [255] + + $ killdaemons.py + +web.allow-pull=false denies read access to repo + + $ cat > .hg/hgrc < [web] + > allow-pull = false + > EOF + + $ hg serve -p $HGPORT -d --pid-file hg.pid + $ cat hg.pid > $DAEMON_PIDS + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=capabilities' + 401 pull not authorized + + 0 + pull not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases' + 401 pull not authorized + + 0 + pull not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases' + 401 pull not authorized + + 0 + pull not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm' + 405 push requires POST request + + 0 + push requires POST request + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm' + 401 pull not authorized + + 0 + pull not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm' + 405 push requires POST request + + 0 + push requires POST request + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm' + 405 push requires POST request + + 0 + push requires POST request + [1] + + $ hg --cwd ../test2 pull http://localhost:$HGPORT/ + pulling from http://localhost:$HGPORT/ + abort: authorization failed + [255] + + $ killdaemons.py + +Attempting a write command with HTTP GET fails + + $ cat > .hg/hgrc < EOF + + $ REQUEST_METHOD=GET hg serve -p $HGPORT -d --pid-file hg.pid + $ cat hg.pid > $DAEMON_PIDS + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b' + 405 push requires POST request + + 0 + push requires POST request + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b' + 405 push requires POST request + + 0 + push requires POST request + [1] + + $ hg bookmarks + no bookmarks set + $ hg bookmark -d bm + abort: bookmark 'bm' does not exist + [255] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm' + 405 push requires POST request + + 0 + push requires POST request + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm' + 405 push requires POST request + + 0 + push requires POST request + [1] + + $ killdaemons.py + +Attempting a write command with an unknown HTTP verb fails + + $ REQUEST_METHOD=someverb hg serve -p $HGPORT -d --pid-file hg.pid + $ cat hg.pid > $DAEMON_PIDS + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b' + 405 push requires POST request + + 0 + push requires POST request + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b' + 405 push requires POST request + + 0 + push requires POST request + [1] + + $ hg bookmarks + no bookmarks set + $ hg bookmark -d bm + abort: bookmark 'bm' does not exist + [255] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm' + 405 push requires POST request + + 0 + push requires POST request + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm' + 405 push requires POST request + + 0 + push requires POST request + [1] + + $ killdaemons.py + +Pushing on a plaintext channel is disabled by default + + $ cat > .hg/hgrc < EOF + + $ REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid + $ cat hg.pid > $DAEMON_PIDS + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b' + 403 ssl required + + 0 + ssl required + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b' + 403 ssl required + + 0 + ssl required + [1] + + $ hg bookmarks + no bookmarks set + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm' + 403 ssl required + + 0 + ssl required + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm' + 403 ssl required + + 0 + ssl required + [1] + +Reset server to remove REQUEST_METHOD hack to test hg client + + $ killdaemons.py + $ hg serve -p $HGPORT -d --pid-file hg.pid + $ cat hg.pid > $DAEMON_PIDS + + $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/ + pushing to http://localhost:$HGPORT/ + searching for changes + no changes found + abort: HTTP Error 403: ssl required + [255] + + $ hg --cwd ../test2 push http://localhost:$HGPORT/ + pushing to http://localhost:$HGPORT/ + searching for changes + abort: HTTP Error 403: ssl required + [255] + + $ killdaemons.py + +web.deny_push=* denies pushing to unauthenticated users + + $ cat > .hg/hgrc < [web] + > push_ssl = false + > deny_push = * + > EOF + + $ REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid + $ cat hg.pid > $DAEMON_PIDS + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b' + 401 push not authorized + + 0 + push not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b' + 401 push not authorized + + 0 + push not authorized + [1] + + $ hg bookmarks + no bookmarks set + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm' + 401 push not authorized + + 0 + push not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm' + 401 push not authorized + + 0 + push not authorized + [1] + +Reset server to remove REQUEST_METHOD hack to test hg client + + $ killdaemons.py + $ hg serve -p $HGPORT -d --pid-file hg.pid + $ cat hg.pid > $DAEMON_PIDS + + $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/ + pushing to http://localhost:$HGPORT/ + searching for changes + no changes found + abort: authorization failed + [255] + + $ hg --cwd ../test2 push http://localhost:$HGPORT/ + pushing to http://localhost:$HGPORT/ + searching for changes + abort: authorization failed + [255] + + $ killdaemons.py + +web.deny_push=* denies pushing to authenticated users + + $ REMOTE_USER=someuser REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid + $ cat hg.pid > $DAEMON_PIDS + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b' + 401 push not authorized + + 0 + push not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b' + 401 push not authorized + + 0 + push not authorized + [1] + + $ hg bookmarks + no bookmarks set + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm' + 401 push not authorized + + 0 + push not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm' + 401 push not authorized + + 0 + push not authorized + [1] + +Reset server to remove REQUEST_METHOD hack to test hg client + + $ killdaemons.py + $ REMOTE_USER=someuser hg serve -p $HGPORT -d --pid-file hg.pid + $ cat hg.pid > $DAEMON_PIDS + + $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/ + pushing to http://localhost:$HGPORT/ + searching for changes + no changes found + abort: authorization failed + [255] + + $ hg --cwd ../test2 push http://localhost:$HGPORT/ + pushing to http://localhost:$HGPORT/ + searching for changes + abort: authorization failed + [255] + + $ killdaemons.py + +web.deny_push= denies pushing to user in list + + $ cat > .hg/hgrc < [web] + > push_ssl = false + > deny_push = baduser + > EOF + + $ REMOTE_USER=baduser REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid + $ cat hg.pid > $DAEMON_PIDS + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b' + 401 push not authorized + + 0 + push not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b' + 401 push not authorized + + 0 + push not authorized + [1] + + $ hg bookmarks + no bookmarks set + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm' + 401 push not authorized + + 0 + push not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm' + 401 push not authorized + + 0 + push not authorized + [1] + +Reset server to remove REQUEST_METHOD hack to test hg client + + $ killdaemons.py + $ REMOTE_USER=baduser hg serve -p $HGPORT -d --pid-file hg.pid + $ cat hg.pid > $DAEMON_PIDS + + $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/ + pushing to http://localhost:$HGPORT/ + searching for changes + no changes found + abort: authorization failed + [255] + + $ hg --cwd ../test2 push http://localhost:$HGPORT/ + pushing to http://localhost:$HGPORT/ + searching for changes + abort: authorization failed + [255] + + $ killdaemons.py + +web.deny_push= denies pushing to user not in list because allow-push isn't set + + $ REMOTE_USER=gooduser REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid + $ cat hg.pid > $DAEMON_PIDS + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b' + 401 push not authorized + + 0 + push not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b' + 401 push not authorized + + 0 + push not authorized + [1] + + $ hg bookmarks + no bookmarks set + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm' + 401 push not authorized + + 0 + push not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm' + 401 push not authorized + + 0 + push not authorized + [1] + +Reset server to remove REQUEST_METHOD hack to test hg client + + $ killdaemons.py + $ REMOTE_USER=gooduser hg serve -p $HGPORT -d --pid-file hg.pid + $ cat hg.pid > $DAEMON_PIDS + + $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/ + pushing to http://localhost:$HGPORT/ + searching for changes + no changes found + abort: authorization failed + [255] + + $ hg --cwd ../test2 push http://localhost:$HGPORT/ + pushing to http://localhost:$HGPORT/ + searching for changes + abort: authorization failed + [255] + + $ killdaemons.py + +web.allow-push=* allows pushes from unauthenticated users + + $ cat > .hg/hgrc < [web] + > push_ssl = false + > allow-push = * + > EOF + + $ REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid + $ cat hg.pid > $DAEMON_PIDS + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b' + 200 Script output follows + + 1 + + $ hg bookmarks + bm 0:cb9a9f314b8b + $ hg book -d bm + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm' + 200 Script output follows + + write command no defined permissions + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm' + 200 Script output follows + + write command w/ defined permissions + +Reset server to remove REQUEST_METHOD hack to test hg client + + $ killdaemons.py + $ hg serve -p $HGPORT -d --pid-file hg.pid + $ cat hg.pid > $DAEMON_PIDS + + $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/ + pushing to http://localhost:$HGPORT/ + searching for changes + no changes found + exporting bookmark bm + [1] + + $ hg book -d bm + + $ hg --cwd ../test2 push http://localhost:$HGPORT/ + pushing to http://localhost:$HGPORT/ + searching for changes + remote: adding changesets + remote: adding manifests + remote: adding file changes + remote: added 1 changesets with 1 changes to 1 files + + $ hg strip -r 1: + saved backup bundle to $TESTTMP/test/.hg/strip-backup/ba677d0156c1-eea704d7-backup.hg + + $ killdaemons.py + +web.allow-push=* allows pushes from authenticated users + + $ REMOTE_USER=someuser REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid + $ cat hg.pid > $DAEMON_PIDS + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b' + 200 Script output follows + + 1 + + $ hg bookmarks + bm 0:cb9a9f314b8b + $ hg book -d bm + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm' + 200 Script output follows + + write command no defined permissions + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm' + 200 Script output follows + + write command w/ defined permissions + +Reset server to remove REQUEST_METHOD hack to test hg client + + $ killdaemons.py + $ REMOTE_USER=someuser hg serve -p $HGPORT -d --pid-file hg.pid + $ cat hg.pid > $DAEMON_PIDS + + $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/ + pushing to http://localhost:$HGPORT/ + searching for changes + no changes found + exporting bookmark bm + [1] + + $ hg book -d bm + + $ hg --cwd ../test2 push http://localhost:$HGPORT/ + pushing to http://localhost:$HGPORT/ + searching for changes + remote: adding changesets + remote: adding manifests + remote: adding file changes + remote: added 1 changesets with 1 changes to 1 files + + $ hg strip -r 1: + saved backup bundle to $TESTTMP/test/.hg/strip-backup/ba677d0156c1-eea704d7-backup.hg + + $ killdaemons.py + +web.allow-push= denies push to user not in list + + $ cat > .hg/hgrc < [web] + > push_ssl = false + > allow-push = gooduser + > EOF + + $ REMOTE_USER=baduser REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid + $ cat hg.pid > $DAEMON_PIDS + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b' + 401 push not authorized + + 0 + push not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b' + 401 push not authorized + + 0 + push not authorized + [1] + + $ hg bookmarks + no bookmarks set + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm' + 401 push not authorized + + 0 + push not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm' + 401 push not authorized + + 0 + push not authorized + [1] + +Reset server to remove REQUEST_METHOD hack to test hg client + + $ killdaemons.py + $ REMOTE_USER=baduser hg serve -p $HGPORT -d --pid-file hg.pid + $ cat hg.pid > $DAEMON_PIDS + + $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/ + pushing to http://localhost:$HGPORT/ + searching for changes + no changes found + abort: authorization failed + [255] + + $ hg --cwd ../test2 push http://localhost:$HGPORT/ + pushing to http://localhost:$HGPORT/ + searching for changes + abort: authorization failed + [255] + + $ killdaemons.py + +web.allow-push= allows push from user in list + + $ REMOTE_USER=gooduser REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid + $ cat hg.pid > $DAEMON_PIDS + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b' + 200 Script output follows + + 1 + + $ hg bookmarks + bm 0:cb9a9f314b8b + $ hg book -d bm + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b' + 200 Script output follows + + 1 + + $ hg bookmarks + bm 0:cb9a9f314b8b + $ hg book -d bm + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm' + 200 Script output follows + + write command no defined permissions + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm' + 200 Script output follows + + write command w/ defined permissions + +Reset server to remove REQUEST_METHOD hack to test hg client + + $ killdaemons.py + $ REMOTE_USER=gooduser hg serve -p $HGPORT -d --pid-file hg.pid + $ cat hg.pid > $DAEMON_PIDS + + $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/ + pushing to http://localhost:$HGPORT/ + searching for changes + no changes found + exporting bookmark bm + [1] + + $ hg book -d bm + + $ hg --cwd ../test2 push http://localhost:$HGPORT/ + pushing to http://localhost:$HGPORT/ + searching for changes + remote: adding changesets + remote: adding manifests + remote: adding file changes + remote: added 1 changesets with 1 changes to 1 files + + $ hg strip -r 1: + saved backup bundle to $TESTTMP/test/.hg/strip-backup/ba677d0156c1-eea704d7-backup.hg + + $ killdaemons.py + +web.deny_push takes precedence over web.allow_push + + $ cat > .hg/hgrc < [web] + > push_ssl = false + > allow-push = someuser + > deny_push = someuser + > EOF + + $ REMOTE_USER=someuser REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid + $ cat hg.pid > $DAEMON_PIDS + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b' + 401 push not authorized + + 0 + push not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b' + 401 push not authorized + + 0 + push not authorized + [1] + + $ hg bookmarks + no bookmarks set + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm' + 401 push not authorized + + 0 + push not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm' + 401 push not authorized + + 0 + push not authorized + [1] + +Reset server to remove REQUEST_METHOD hack to test hg client + + $ killdaemons.py + $ REMOTE_USER=someuser hg serve -p $HGPORT -d --pid-file hg.pid + $ cat hg.pid > $DAEMON_PIDS + + $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/ + pushing to http://localhost:$HGPORT/ + searching for changes + no changes found + abort: authorization failed + [255] + + $ hg --cwd ../test2 push http://localhost:$HGPORT/ + pushing to http://localhost:$HGPORT/ + searching for changes + abort: authorization failed + [255] + + $ killdaemons.py + +web.allow-push has no effect if web.deny_read is set + + $ cat > .hg/hgrc < [web] + > push_ssl = false + > allow-push = * + > deny_read = * + > EOF + + $ REQUEST_METHOD=POST REMOTE_USER=someuser hg serve -p $HGPORT -d --pid-file hg.pid + $ cat hg.pid > $DAEMON_PIDS + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b' + 401 read not authorized + + 0 + read not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b' + 401 read not authorized + + 0 + read not authorized + [1] + + $ hg bookmarks + no bookmarks set + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm' + 401 read not authorized + + 0 + read not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm' + 401 read not authorized + + 0 + read not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm' + 401 read not authorized + + 0 + read not authorized + [1] + + $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm' + 401 read not authorized + + 0 + read not authorized + [1] + +Reset server to remove REQUEST_METHOD hack to test hg client + + $ killdaemons.py + $ REMOTE_USER=someuser hg serve -p $HGPORT -d --pid-file hg.pid + $ cat hg.pid > $DAEMON_PIDS + + $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/ + pushing to http://localhost:$HGPORT/ + abort: authorization failed + [255] + + $ hg --cwd ../test2 push http://localhost:$HGPORT/ + pushing to http://localhost:$HGPORT/ + abort: authorization failed + [255] + + $ killdaemons.py diff --git a/tests/test-http.t b/tests/test-http.t --- a/tests/test-http.t +++ b/tests/test-http.t @@ -254,6 +254,7 @@ test http authentication http auth: user user, password **** sending capabilities command devel-peer-request: GET http://localhost:$HGPORT2/?cmd=capabilities + http auth: user user, password **** devel-peer-request: finished in *.???? seconds (200) (glob) query 1; heads sending batch command @@ -270,7 +271,6 @@ test http authentication devel-peer-request: Vary X-HgArg-1,X-HgProto-1 devel-peer-request: X-hgproto-1 0.1 0.2 comp=$USUAL_COMPRESSIONS$ devel-peer-request: 16 bytes of commands arguments in headers - http auth: user user, password **** devel-peer-request: finished in *.???? seconds (200) (glob) received listkey for "phases": 58 bytes checking for updated bookmarks @@ -340,57 +340,49 @@ test http authentication $ hg rollback -q $ sed 's/.*] "/"/' < ../access.log - "GET /?cmd=capabilities HTTP/1.1" 200 - - "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ - "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ + "GET /?cmd=capabilities HTTP/1.1" 401 - + "GET /?cmd=capabilities HTTP/1.1" 401 - + "GET /?cmd=capabilities HTTP/1.1" 401 - "GET /?cmd=capabilities HTTP/1.1" 200 - "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ - "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ + "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ + "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ + "GET /?cmd=capabilities HTTP/1.1" 401 - "GET /?cmd=capabilities HTTP/1.1" 200 - "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ - "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ - "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ - "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ - "GET /?cmd=capabilities HTTP/1.1" 200 - - "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ - "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ + "GET /?cmd=capabilities HTTP/1.1" 401 - "GET /?cmd=capabilities HTTP/1.1" 200 - "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ - "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ + "GET /?cmd=capabilities HTTP/1.1" 401 - "GET /?cmd=capabilities HTTP/1.1" 200 - "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ - "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ + "GET /?cmd=capabilities HTTP/1.1" 401 - "GET /?cmd=capabilities HTTP/1.1" 200 - "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ - "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ + "GET /?cmd=capabilities HTTP/1.1" 401 - "GET /?cmd=capabilities HTTP/1.1" 200 - "GET /?cmd=branchmap HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ - "GET /?cmd=stream_out HTTP/1.1" 401 - x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ "GET /?cmd=stream_out HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D5fed3813f7f5e1824344fdc9cf8f63bb662c292d x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ "GET /?cmd=getbundle HTTP/1.1" 200 - x-hgarg-1:bookmarks=1&$USUAL_BUNDLE_CAPS$&cg=0&common=5fed3813f7f5e1824344fdc9cf8f63bb662c292d&heads=5fed3813f7f5e1824344fdc9cf8f63bb662c292d&listkeys=bookmarks&phases=1 x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ + "GET /?cmd=capabilities HTTP/1.1" 401 - "GET /?cmd=capabilities HTTP/1.1" 200 - "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ - "GET /?cmd=getbundle HTTP/1.1" 401 - x-hgarg-1:bookmarks=1&$USUAL_BUNDLE_CAPS$&cg=1&common=0000000000000000000000000000000000000000&heads=5fed3813f7f5e1824344fdc9cf8f63bb662c292d&listkeys=bookmarks&phases=1 x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ "GET /?cmd=getbundle HTTP/1.1" 200 - x-hgarg-1:bookmarks=1&$USUAL_BUNDLE_CAPS$&cg=1&common=0000000000000000000000000000000000000000&heads=5fed3813f7f5e1824344fdc9cf8f63bb662c292d&listkeys=bookmarks&phases=1 x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ - "GET /?cmd=capabilities HTTP/1.1" 200 - - "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ - "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ - "GET /?cmd=capabilities HTTP/1.1" 200 - - "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ - "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ - "GET /?cmd=listkeys HTTP/1.1" 403 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ + "GET /?cmd=capabilities HTTP/1.1" 401 - + "GET /?cmd=capabilities HTTP/1.1" 401 - + "GET /?cmd=capabilities HTTP/1.1" 403 - + "GET /?cmd=capabilities HTTP/1.1" 401 - "GET /?cmd=capabilities HTTP/1.1" 200 - "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D7f4e523d01f2cc3765ac8934da3d14db775ff872 x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ - "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ "GET /?cmd=branchmap HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ @@ -398,9 +390,9 @@ test http authentication "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ "POST /?cmd=unbundle HTTP/1.1" 200 - x-hgarg-1:heads=666f726365* (glob) "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ + "GET /?cmd=capabilities HTTP/1.1" 401 - "GET /?cmd=capabilities HTTP/1.1" 200 - "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D7f4e523d01f2cc3765ac8934da3d14db775ff872 x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ - "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ "GET /?cmd=branchmap HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ diff --git a/tests/test-largefiles-wireproto.t b/tests/test-largefiles-wireproto.t --- a/tests/test-largefiles-wireproto.t +++ b/tests/test-largefiles-wireproto.t @@ -444,11 +444,11 @@ a large file from the server rather than > EOF $ hg clone --config ui.interactive=true --config extensions.getpass=get_pass.py \ > http://user@localhost:$HGPORT credentialclone - requesting all changes http authorization required for http://localhost:$HGPORT/ realm: mercurial user: user - password: adding changesets + password: requesting all changes + adding changesets adding manifests adding file changes added 1 changesets with 1 changes to 1 files diff --git a/tests/test-lfs-bundle.t b/tests/test-lfs-bundle.t new file mode 100644 --- /dev/null +++ b/tests/test-lfs-bundle.t @@ -0,0 +1,97 @@ +In this test, we want to test LFS bundle application on both LFS and non-LFS +repos. + +To make it more interesting, the file revisions will contain hg filelog +metadata ('\1\n'). The bundle will have 1 file revision overlapping with the +destination repo. + +# rev 1 2 3 +# repo: yes yes no +# bundle: no (base) yes yes (deltabase: 2 if possible) + +It is interesting because rev 2 could have been stored as LFS in the repo, and +non-LFS in the bundle; or vice-versa. + +Init + + $ cat >> $HGRCPATH << EOF + > [extensions] + > lfs= + > drawdag=$TESTDIR/drawdag.py + > [lfs] + > url=file:$TESTTMP/lfs-remote + > EOF + +Helper functions + + $ commitxy() { + > hg debugdrawdag "$@" <<'EOS' + > Y # Y/X=\1\nAAAA\nE\nF + > | # Y/Y=\1\nAAAA\nG\nH + > X # X/X=\1\nAAAA\nC\n + > # X/Y=\1\nAAAA\nD\n + > EOS + > } + + $ commitz() { + > hg debugdrawdag "$@" <<'EOS' + > Z # Z/X=\1\nAAAA\nI\n + > | # Z/Y=\1\nAAAA\nJ\n + > | # Z/Z=\1\nZ + > Y + > EOS + > } + + $ enablelfs() { + > cat >> .hg/hgrc < [lfs] + > track=all() + > EOF + > } + +Generate bundles + + $ for i in normal lfs; do + > NAME=src-$i + > hg init $TESTTMP/$NAME + > cd $TESTTMP/$NAME + > [ $i = lfs ] && enablelfs + > commitxy + > commitz + > hg bundle -q --base X -r Y+Z $TESTTMP/$NAME.bundle + > SRCNAMES="$SRCNAMES $NAME" + > done + +Prepare destination repos + + $ for i in normal lfs; do + > NAME=dst-$i + > hg init $TESTTMP/$NAME + > cd $TESTTMP/$NAME + > [ $i = lfs ] && enablelfs + > commitxy + > DSTNAMES="$DSTNAMES $NAME" + > done + +Apply bundles + + $ for i in $SRCNAMES; do + > for j in $DSTNAMES; do + > echo ---- Applying $i.bundle to $j ---- + > cp -R $TESTTMP/$j $TESTTMP/tmp-$i-$j + > cd $TESTTMP/tmp-$i-$j + > if hg unbundle $TESTTMP/$i.bundle -q 2>/dev/null; then + > hg verify -q && echo OK + > else + > echo CRASHED + > fi + > done + > done + ---- Applying src-normal.bundle to dst-normal ---- + OK + ---- Applying src-normal.bundle to dst-lfs ---- + OK + ---- Applying src-lfs.bundle to dst-normal ---- + OK + ---- Applying src-lfs.bundle to dst-lfs ---- + OK diff --git a/tests/test-lfs.t b/tests/test-lfs.t --- a/tests/test-lfs.t +++ b/tests/test-lfs.t @@ -371,7 +371,7 @@ enabled adds the lfs requirement uncompressed size of bundle content: * (changelog) (glob) * (manifests) (glob) - * a (glob) + * a (glob) $ hg --config extensions.strip= strip -r 2 --no-backup --force -q $ hg -R bundle.hg log -p -T '{rev} {desc}\n' a 5 branching diff --git a/tests/test-pull-http.t b/tests/test-pull-http.t --- a/tests/test-pull-http.t +++ b/tests/test-pull-http.t @@ -50,7 +50,6 @@ expect error, cloning not allowed $ hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log $ cat hg.pid >> $DAEMON_PIDS $ hg clone http://localhost:$HGPORT/ test4 # bundle2+ - requesting all changes abort: authorization failed [255] $ hg clone http://localhost:$HGPORT/ test4 --config devel.legacy.exchange=bundle1 @@ -74,7 +73,6 @@ expect error, pulling not allowed $ req pulling from http://localhost:$HGPORT/ - searching for changes abort: authorization failed % serve errors diff --git a/tests/test-push-http.t b/tests/test-push-http.t --- a/tests/test-push-http.t +++ b/tests/test-push-http.t @@ -307,28 +307,6 @@ Make phases updates work $ hg --config extensions.strip= strip -r 1: saved backup bundle to $TESTTMP/test/.hg/strip-backup/ba677d0156c1-eea704d7-backup.hg -expect authorization error: all users denied - - $ echo '[web]' > .hg/hgrc - $ echo 'push_ssl = false' >> .hg/hgrc - $ echo 'deny_push = *' >> .hg/hgrc - $ req - pushing to http://localhost:$HGPORT/ - searching for changes - abort: authorization failed - % serve errors - [255] - -expect authorization error: some users denied, users must be authenticated - - $ echo 'deny_push = unperson' >> .hg/hgrc - $ req - pushing to http://localhost:$HGPORT/ - searching for changes - abort: authorization failed - % serve errors - [255] - #if bundle2 $ cat > .hg/hgrc < -1) != isdelta: - abort('rev %d: isdelta is ineffective' % rev) + # isdelta can be overridden to False if this or p1 has isext set + if bool(rlog.deltaparent(rev) > -1) and not isdelta: + abort('rev %d: isdelta is unexpected' % rev) if bool(rlog.flags(rev)) != isext: abort('rev %d: isext is ineffective' % rev) return result